124

或者更一般地说,如何从 Bash 环境变量中以冒号分隔的列表中删除项目?

我以为我在几年前看到了一种简单的方法,使用更高级的 Bash 变量扩展形式,但如果是这样,我已经忘记了它。对 Google 的快速搜索结果出乎意料地少,而且没有一个我称之为“简单”或“优雅”的结果。例如,分别使用 sed 和 awk 的两种方法:

PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)

没有直接的东西存在吗?有什么类似于 Bash 中的 split() 函数的吗?

更新:
看来我需要为我故意含糊的问题道歉;我对解决特定用例的兴趣不如对引发良好讨论的兴趣。幸运的是,我明白了!

这里有一些非常聪明的技巧。最后,我在我的工具箱中添加了以下三个功能。魔术发生在 path_remove 中,它主要基于 Martin York 巧妙地使用awk's RS 变量。

path_append ()  { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove ()  { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }

那里唯一真正的麻烦是使用sed删除尾随冒号。不过,考虑到 Martin 的解决方案的其余部分是多么简单,我非常愿意接受它!


相关问题:如何在 shell 脚本中操作 $PATH 元素?

4

34 回答 34

63

我的肮脏黑客:

echo ${PATH} > t1
vi t1
export PATH=$(cat t1)
于 2008-12-16T00:05:01.580 回答
57

awk 一分钟:

# Strip all paths with SDE in them.
#
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`

编辑:它回应以下评论:

$ export a="/a/b/c/d/e:/a/b/c/d/g/k/i:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i"
$ echo ${a}
/a/b/c/d/e:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i

## Remove multiple (any directory with a: all of them)
$ echo ${a} | awk -v RS=: -v ORS=: '/a/ {next} {print}'
## Works fine all removed

## Remove multiple including last two: (any directory with g)
$ echo ${a} | awk -v RS=: -v ORS=: '/g/ {next} {print}'
/a/b/c/d/e:/a/b/c/d/f:
## Works fine: Again!

针对安全问题进行编辑:(与问题无关)

export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')

这会删除通过删除最后一个条目留下的任何尾随冒号,这将有效地添加.到您的路径中。

于 2008-12-16T00:40:34.223 回答
48

既然替换的最大问题是结束情况,那么如何使结束情况与其他情况没有什么不同呢?如果路径的开头和结尾已经有冒号,我们可以简单地搜索用冒号包裹的所需字符串。事实上,我们可以轻松地添加这些冒号并在之后删除它们。

# PATH => /bin:/opt/a dir/bin:/sbin
WORK=:$PATH:
# WORK => :/bin:/opt/a dir/bin:/sbin:
REMOVE='/opt/a dir/bin'
WORK=${WORK/:$REMOVE:/:}
# WORK => :/bin:/sbin:
WORK=${WORK%:}
WORK=${WORK#:}
PATH=$WORK
# PATH => /bin:/sbin

纯 bash :)。

于 2010-01-21T10:48:53.013 回答
27

这是我可以设计的最简单的解决方案:

#!/bin/bash
IFS=:
# convert it to an array
t=($PATH)
unset IFS
# perform any array operations to remove elements from the array
t=(${t[@]%%*usr*})
IFS=:
# output the new array
echo "${t[*]}"

上面的示例将删除 $PATH 中包含“usr”的任何元素。您可以将“*usr*”替换为“/home/user/bin”以仅删除该元素。

sschuberth更新

尽管我认为 a 中的空格$PATH是一个可怕的想法,但这里有一个处理它的解决方案:

PATH=$(IFS=':';t=($PATH);n=${#t[*]};a=();for ((i=0;i<n;i++)); do p="${t[i]%%*usr*}"; [ "${p}" ] && a[i]="${p}"; done;echo "${a[*]}");

或者

IFS=':'
t=($PATH)
n=${#t[*]}
a=()
for ((i=0;i<n;i++)); do
  p="${t[i]%%*usr*}"
  [ "${p}" ] && a[i]="${p}"
done
echo "${a[*]}"
于 2008-12-16T01:27:12.710 回答
13

这是一个单行代码,尽管当前已接受评价最高的答案,但不会将不可见字符添加到 PATH 并且可以处理包含空格的路径:

export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:})

就个人而言,我也觉得这很容易阅读/理解,而且它只涉及常用命令而不是使用 awk。

于 2012-10-30T08:39:27.573 回答
11

这是一个解决方案:

  • 是纯 Bash,
  • 不调用其他进程(如“sed”或“awk”),
  • 不变IFS
  • 不分叉子外壳,
  • 处理带空格的路径,以及
  • 删除 中所有出现的参数PATH

    removeFromPath() {
       本地 pd
       p=":$1:"
       d=":$PATH:"
       d=${d//$p/:}
       d=${d/#:/}
       路径=${d/%:/}
    }
于 2015-03-20T04:22:43.913 回答
7

到目前为止,我发现的最好的纯 bash 选项如下:

function path_remove {
  PATH=${PATH/":$1"/} # delete any instances in the middle or at the end
  PATH=${PATH/"$1:"/} # delete any instances at the beginning
}

这是基于对将目录添加到 $PATH 的不完全正确的答案如果它在超级用户上还没有。

于 2013-10-25T10:59:30.090 回答
6
function __path_remove(){  
    local D=":${PATH}:";  
    [ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
}  

从我的 .bashrc 文件中挖出来。当您使用 PATH 时,它会丢失,awk/sed/grep 变得不可用:-)

于 2012-08-13T00:28:39.617 回答
5

我一直在使用 bash 发行版中的函数,这些函数显然自 1991 年以来就已经存在。这些仍然在 Fedora 上的 bash-docs 包中,并且曾经在/etc/profile.

$ rpm -ql bash-doc |grep pathfunc
/usr/share/doc/bash-4.2.20/examples/functions/pathfuncs
$ cat $(!!)
cat $(rpm -ql bash-doc |grep pathfunc)
#From: "Simon J. Gerraty" <sjg@zen.void.oz.au>
#Message-Id: <199510091130.VAA01188@zen.void.oz.au>
#Subject: Re: a shell idea?
#Date: Mon, 09 Oct 1995 21:30:20 +1000


# NAME:
#       add_path.sh - add dir to path
#
# DESCRIPTION:
#       These functions originated in /etc/profile and ksh.kshrc, but
#       are more useful in a separate file.
#
# SEE ALSO:
#       /etc/profile
#
# AUTHOR:
#       Simon J. Gerraty <sjg@zen.void.oz.au>

#       @(#)Copyright (c) 1991 Simon J. Gerraty
#
#       This file is provided in the hope that it will
#       be of use.  There is absolutely NO WARRANTY.
#       Permission to copy, redistribute or otherwise
#       use this file is hereby granted provided that
#       the above copyright notice and this notice are
#       left intact.

# is $1 missing from $2 (or PATH) ?
no_path() {
        eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}
于 2012-03-08T23:09:11.980 回答
4

我确实在这里写了一个答案(也使用 awk)。但我不确定这就是你要找的东西?它至少在我看来很清楚它的作用,而不是试图融入一行。不过,对于一个只去除东西的简单衬里,我建议

echo $PATH | tr ':' '\n' | awk '$0 != "/bin"' | paste -sd:

更换是

echo $PATH | tr ':' '\n' | 
    awk '$0 != "/bin"; $0 == "/bin" { print "/bar" }' | paste -sd:

或(较短但可读性较差)

echo $PATH | tr ':' '\n' | awk '$0 == "/bin" { print "/bar"; next } 1' | paste -sd:

无论如何,对于同一个问题,以及很多有用的答案,请参见此处

于 2008-12-16T00:13:48.723 回答
3

好吧,在 bash 中,因为它支持正则表达式,所以我会这样做:

PATH=${PATH/:\/home\/user\/bin/}
于 2008-12-15T23:23:54.487 回答
2

我喜欢@BenBlank 对他原始问题的更新中显示的三个函数。为了概括它们,我使用 2 参数形式,它允许我设置 PATH 或我想要的任何其他环境变量:

path_append ()  { path_remove $1 $2; export $1="${!1}:$2"; }
path_prepend () { path_remove $1 $2; export $1="$2:${!1}"; }
path_remove ()  { export $1="`echo -n ${!1} | awk -v RS=: -v ORS=: '$1 != "'$2'"' | sed 's/:$//'`"; }

使用示例:

path_prepend PATH /usr/local/bin
path_append PERL5LIB "$DEVELOPMENT_HOME/p5/src/perlmods"

请注意,我还添加了一些引号以允许正确处理包含空格的路径名。

于 2016-01-05T20:54:22.047 回答
2

从 Bash 中的 $PATH 变量中删除路径的最优雅的方法是什么?

还有什么比 awk 更优雅的呢?

path_remove ()  { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; 

Python!这是一个更具可读性和可维护性的解决方案,并且很容易检查它是否真的在做你想要的。

假设您要删除第一个路径元素?

PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"

echo(而不是来自,的管道os.getenv['PATH']会更短一些,并提供与上述相同的结果,但我担心 Python 可能会对那个环境变量做一些事情,所以最好直接从你关心的环境中管道它.)

类似地从最后删除:

PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"

例如,要使这些可重用的 shell 函数可以粘贴在 .bashrc 文件中:

strip_path_first () {
    PATH="$(echo "$PATH" | 
    python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"
}

strip_path_last () {
    PATH="$(echo "$PATH" | 
    python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
}
于 2016-07-10T13:08:56.507 回答
1

是的,例如,在 PATH 的末尾放置一个冒号可以使删除路径变得不那么笨拙和容易出错。

path_remove ()  { 
   declare i newPATH
   newPATH="${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      #echo ${@:${i}:1}
      newPATH="${newPATH//${@:${i}:1}:/}" 
   done
   export PATH="${newPATH%:}" 
   return 0; 
} 

path_remove_all ()  {
   declare i newPATH
   shopt -s extglob
   newPATH="${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      newPATH="${newPATH//+(${@:${i}:1})*([^:]):/}" 
      #newPATH="${newPATH//+(${@:${i}:1})*([^:])+(:)/}" 
   done
   shopt -u extglob 
   export PATH="${newPATH%:}" 
   return 0 
} 

path_remove /opt/local/bin /usr/local/bin

path_remove_all /opt/local /usr/local 
于 2010-01-21T19:58:30.380 回答
1

如果您担心删除$PATH 中的重复项,最优雅的方式,恕我直言,首先不要添加它们。在 1 行中:

if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi

$folder 可以替换为任何内容,并且可以包含空格(“/home/user/my documents”)

于 2011-02-19T05:11:25.150 回答
1

迄今为止我发现的最优雅的纯 bash 解决方案:

pathrm () {                                                                      
  local IFS=':'                                                                  
  local newpath                                                                  
  local dir                                                                      
  local pathvar=${2:-PATH}                                                       
  for dir in ${!pathvar} ; do                                                    
    if [ "$dir" != "$1" ] ; then                                                 
      newpath=${newpath:+$newpath:}$dir                                          
    fi                                                                           
  done                                                                           
  export $pathvar="$newpath"                                                        
}

pathprepend () {                                                                 
  pathrm $1 $2                                                                   
  local pathvar=${2:-PATH}                                                       
  export $pathvar="$1${!pathvar:+:${!pathvar}}"                                  
}

pathappend () {                                                                    
  pathrm $1 $2                                                                   
  local pathvar=${2:-PATH}                                                       
  export $pathvar="${!pathvar:+${!pathvar}:}$1"                                  
} 
于 2012-04-07T05:29:34.720 回答
1

大多数其他建议的解决方案仅依赖于字符串匹配,不考虑包含特殊名称的路径段,如.,..~. 下面的 bash 函数解析其参数和路径段中的目录字符串,以查找逻辑目录匹配以及字符串匹配。

rm_from_path() {
  pattern="${1}"
  dir=''
  [ -d "${pattern}" ] && dir="$(cd ${pattern} && pwd)"  # resolve to absolute path

  new_path=''
  IFS0=${IFS}
  IFS=':'
  for segment in ${PATH}; do
    if [[ ${segment} == ${pattern} ]]; then             # string match
      continue
    elif [[ -n ${dir} && -d ${segment} ]]; then
      segment="$(cd ${segment} && pwd)"                 # resolve to absolute path
      if [[ ${segment} == ${dir} ]]; then               # logical directory match
        continue
      fi
    fi
    new_path="${new_path}${IFS}${segment}"
  done
  new_path="${new_path/#${IFS}/}"                       # remove leading colon, if any
  IFS=${IFS0}

  export PATH=${new_path}
}

测试:

$ mkdir -p ~/foo/bar/baz ~/foo/bar/bif ~/foo/boo/bang
$ PATH0=${PATH}
$ PATH=~/foo/bar/baz/.././../boo/././../bar:${PATH}  # add dir with special names
$ rm_from_path ~/foo/boo/../bar/.  # remove same dir with different special names
$ [ ${PATH} == ${PATH0} ] && echo 'PASS' || echo 'FAIL'
于 2014-09-22T23:16:25.293 回答
1

来自 Scratch 的 Linux 定义了三个 Bash 函数/etc/profile

# Functions to help us manage paths.  Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
        local IFS=':'
        local NEWPATH
        local DIR
        local PATHVARIABLE=${2:-PATH}
        for DIR in ${!PATHVARIABLE} ; do
                if [ "$DIR" != "$1" ] ; then
                  NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
                fi
        done
        export $PATHVARIABLE="$NEWPATH"
}

pathprepend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}

pathappend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}

export -f pathremove pathprepend pathappend

参考:http ://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html

于 2015-11-22T10:00:54.283 回答
1

我知道这个问题是关于 BASH 的,每个人都应该喜欢它,但是因为我喜欢对称,有时我需要使用“csh”,所以我构建了与“path_prepend()”、“path_append()”和“path_remove”等价的()" 优雅的解决方案。

要点是“csh”没有函数,所以我在我的个人 bin 目录中放置了一些类似于函数的 shell 脚本。我为 SOURCE 这些脚本创建别名以更改指定的环境变量。

~/bin/_path_remove.csh:

set _resolve = `eval echo $2`
setenv $1 `eval echo -n \$$1 | awk -v RS=: -v ORS=: '$1 != "'${_resolve}'"' | sed 's/:$//'`;
unset _resolve

~/bin/_path_append.csh:

source ~/bin/_path_remove.csh $1 $2
set _base = `eval echo \$$1`
set _resolve = `eval echo $2`
setenv $1 ${_base}:${_resolve}
unset _base _resolve

~/bin/_path_prepend.csh:

source ~/bin/_path_remove.csh $1 $2
set _base = `eval echo \$$1`
set _resolve = `eval echo $2`
setenv $1 ${_resolve}:${_base}
unset _base _resolve

~/bin/.cshrc:

…
alias path_remove  "source ~/bin/_path_remove.csh  '\!:1' '\!:2'"
alias path_append  "source ~/bin/_path_append.csh  '\!:1' '\!:2'"
alias path_prepend "source ~/bin/_path_prepend.csh '\!:1' '\!:2'"
…

你可以像这样使用它们...

%(csh)> path_append MODULEPATH ${HOME}/modulefiles
于 2018-06-08T01:05:05.543 回答
0

由于这往往是相当有问题的,因为没有优雅的方式,我建议通过重新安排解决方案来避免这个问题:建立你的 PATH 而不是试图拆除它。

如果我知道你真正的问题背景,我可以更具体。在此期间,我将使用软件构建作为上下文。

软件构建的一个常见问题是它在某些机器上中断,最终是由于某人如何配置他们的默认 shell(PATH 和其他环境变量)。优雅的解决方案是通过完全指定 shell 环境来使您的构建脚本免疫。对构建脚本进行编码以根据您控制的组装件设置 PATH 和其他环境变量,例如编译器、库、工具、组件等的位置。使每个可配置项成为您可以单独设置、验证和然后在您的脚本中适当使用。

例如,我有一个基于 Maven 的、面向 WebLogic 的 Java 构建,它是我从新雇主那里继承的。构建脚本因脆弱而臭名昭著,我和另一位新员工花了三周时间(不是全职,只是到处,但仍然很多小时)让它在我们的机器上工作。一个重要的步骤是我控制了 PATH,以便我确切地知道正在调用哪个 Java、哪个 Maven 以及哪个 WebLogic。我创建了环境变量来指向这些工具中的每一个,然后我根据这些以及其他一些工具计算了 PATH。类似的技术驯服了其他可配置的设置,直到我们最终创建了一个可重现的构建。

顺便说一句,不要使用 Maven,Java 是可以的,只有在绝对需要它的集群时才购买 WebLogic(否则不需要,尤其是不需要它的专有特性)。

最良好的祝愿。

于 2008-12-16T00:21:26.290 回答
0

与@litb 一样,我为“如何在shell 脚本中操作$PATH 元素”这个问题提供了答案,所以我的主要答案就在那里。

和其他 Bourne shell 派生类中的“拆分”功能bash最巧妙地使用$IFS字段间分隔符来实现。例如,要将位置参数 ( $1, $2, ...) 设置为 PATH 的元素,请使用:

set -- $(IFS=":"; echo "$PATH")

只要 $PATH 中没有空格,它就可以正常工作。让它适用于包含空格的路径元素是一项不平凡的练习 - 留给感兴趣的读者。使用 Perl 等脚本语言处理它可能更简单。

我还有一个脚本,clnpath我广泛使用它来设置我的 PATH。我在“如何避免在 csh 中复制 PATH 变量”的答案中记录了它。

于 2008-12-16T00:43:55.123 回答
0

使这个问题烦人的是第一个和最后一个元素之间的栅栏案例。通过更改 IFS 和使用数组可以优雅地解决该问题,但是我不知道一旦将路径转换为数组形式后如何重新引入冒号。

这是一个稍微不那么优雅的版本,它删除了一个$PATH仅使用字符串操作的目录。我已经测试过了。

#!/bin/bash
#
#   remove_from_path dirname
#
#   removes $1 from user's $PATH

if [ $# -ne 1 ]; then
  echo "Usage: $0 pathname" 1>&2; exit 1;
fi

delendum="$1"
NEWPATH=
xxx="$IFS"
IFS=":"
for i in $PATH ; do
  IFS="$xxx"
  case "$i" in
    "$delendum") ;; # do nothing
    *) [ -z "$NEWPATH" ] && NEWPATH="$i" || NEWPATH="$NEWPATH:$i" ;;
  esac
done

PATH="$NEWPATH"
echo "$PATH"
于 2008-12-16T02:53:52.037 回答
0

这是一个 Perl 单行代码:

PATH=`perl -e '$a=shift;$_=$ENV{PATH};s#:$a(:)|^$a:|:$a$#$1#;print' /home/usr/bin`

$a变量获取要删除的路径。( ssubstitute) 和print命令隐式地对$_变量进行操作。

于 2008-12-16T19:54:14.270 回答
0

好东西在这里。我首先使用这个来避免添加欺骗。

#!/bin/bash
#
######################################################################################
#
# Allows a list of additions to PATH with no dupes
# 
# Patch code below into your $HOME/.bashrc file or where it
# will be seen at login.
#
# Can also be made executable and run as-is.
#
######################################################################################

# add2path=($HOME/bin .)                  ## uncomment space separated list 
if [ $add2path ]; then                    ## skip if list empty or commented out
for nodup in ${add2path[*]}
do
    case $PATH in                 ## case block thanks to MIKE511
    $nodup:* | *:$nodup:* | *:$nodup ) ;;    ## if found, do nothing
    *) PATH=$PATH:$nodup          ## else, add it to end of PATH or
    esac                          ## *) PATH=$nodup:$PATH   prepend to front
done
export PATH
fi
## debug add2path
echo
echo " PATH == $PATH"
echo
于 2010-01-13T01:35:03.457 回答
0

启用扩展 globbing 后,可以执行以下操作:

# delete all /opt/local paths in PATH
shopt -s extglob 
printf "%s\n" "${PATH}" | tr ':' '\n' | nl
printf "%s\n" "${PATH//+(\/opt\/local\/)+([^:])?(:)/}" | tr ':' '\n' | nl 

man bash | less -p extglob
于 2010-01-20T18:28:13.357 回答
0

扩展的 globbing 单线(嗯,有点):

path_remove ()  { shopt -s extglob; PATH="${PATH//+(${1})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 

似乎没有必要在 1 美元中转义斜线。

path_remove ()  { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 
于 2010-01-21T10:14:13.013 回答
0

将冒号添加到 PATH 我们还可以执行以下操作:

path_remove ()  { 
   declare i newPATH
   # put a colon at the beginning & end AND double each colon in-between
   newPATH=":${PATH//:/::}:"   
   for ((i=1; i<=${#@}; i++)); do
       #echo ${@:${i}:1}
       newPATH="${newPATH//:${@:${i}:1}:/}"   # s/:\/fullpath://g
   done
   newPATH="${newPATH//::/:}"
   newPATH="${newPATH#:}"      # remove leading colon
   newPATH="${newPATH%:}"      # remove trailing colon
   unset PATH 
   PATH="${newPATH}" 
   export PATH
   return 0 
} 


path_remove_all ()  {
   declare i newPATH extglobVar
   extglobVar=0
   # enable extended globbing if necessary
   [[ ! $(shopt -q extglob) ]]  && { shopt -s extglob; extglobVar=1; }
   newPATH=":${PATH}:"
   for ((i=1; i<=${#@}; i++ )); do
      newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}"     # s/:\/path[^:]*//g
   done
   newPATH="${newPATH#:}"      # remove leading colon
   newPATH="${newPATH%:}"      # remove trailing colon
   # disable extended globbing if it was enabled in this function
   [[ $extglobVar -eq 1 ]] && shopt -u extglob
   unset PATH 
   PATH="${newPATH}" 
   export PATH
   return 0 
} 

path_remove /opt/local/bin /usr/local/bin

path_remove_all /opt/local /usr/local 
于 2010-01-22T17:45:00.210 回答
0

在 path_remove_all 中(通过代理):

-newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" 
+newPATH="${newPATH//:${@:${i}:1}*([^:])/}"        # s/:\/path[^:]*//g 
于 2010-01-22T18:34:52.513 回答
0

虽然这是一个非常古老的线程,但我认为这个解决方案可能很有趣:

PATH="/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
REMOVE="ccache" # whole or part of a path :)
export PATH=$(IFS=':';p=($PATH);unset IFS;p=(${p[@]%%$REMOVE});IFS=':';echo "${p[*]}";unset IFS)
echo $PATH # outputs /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

在这篇博文中找到它。我想我最喜欢这个了:)

于 2011-06-22T21:18:07.367 回答
0

我采取了与这里的大多数人略有不同的方法,并专门关注字符串操作,如下所示:

path_remove () {
    if [[ ":$PATH:" == *":$1:"* ]]; then
        local dirs=":$PATH:"
        dirs=${dirs/:$1:/:}
        export PATH="$(__path_clean $dirs)"
    fi
}
__path_clean () {
    local dirs=${1%?}
    echo ${dirs#?}
}

以上是我使用的最终函数的简化示例。我还创建path_add_beforepath_add_after允许您在 PATH 中已有的指定路径之前/之后插入路径。

在我的dotfiles中的path_helpers.sh中提供了全套功能。它们完全支持在 PATH 字符串的开头/中间/结尾删除/附加/前置/插入。

于 2012-02-06T01:16:56.410 回答
0

尾随 ':' 是由于您设置的是行尾,而不是分隔符。我使用资源有限的单元,喜欢将所有内容打包到一个脚本中,没有这些奇怪的东西:

path_remove () {
    PATH="$(echo -n $PATH | awk -v RS=: -v ORS= '$0 != "'$1'"{print s _ $0;s=":"}')"
}
于 2014-05-16T19:36:52.920 回答
0

这当然很优雅,但它确实使用了外部 sed。此外,它会删除所有包含搜索字符串 $1 的路径。如果删除的路径是 PATH 上的最后一个,它也不会在最后留下悬空的 :。

PATH=`echo $PATH | sed 's/:[^:]*$1[^:]*//g'`

这个替代方案确实留下了一个悬空的 final : 然而。

PATH=`echo $PATH | tr ":" "\n" | grep -v $1 | tr "\n" ":"`

没有反引号的替代方案是:

PATH=$(echo $PATH | sed 's/:[^:]*$1[^:]*//g')

PATH=$(echo $PATH | tr ":" "\n" | grep -v $1 | tr "\n" ":")
于 2014-10-22T19:06:38.563 回答
0

Bash 内置 oneliner(不删除重复): PATH=${PATH/${PATH/#$DIR:*/$DIR:}/}${PATH/${PATH/*:$DIR*/:$DIR}/}

于 2021-11-23T19:50:26.017 回答
-1

让我们从 PATH 中“删除”对 /path/to/something 的引用:

重击:

PATH=${PATH/something/nope/}

Windows Batch 的奖励答案:

set PATH=%PATH:something=nope%

有人有更简单的解决方案吗?:)

于 2019-04-28T10:51:59.863 回答