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

发布于 2024-07-11 02:53:35 字数 1229 浏览 10 评论 0原文

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

我以为几年前我已经看到了一种简单的方法,使用更高级的 Bash 变量扩展形式,但如果是这样,我已经忘记了它。 谷歌的快速搜索令人惊讶地发现很少有相关结果,而且没有一个我称之为“简单”或“优雅”的结果。 例如,分别使用 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 的 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 删除尾随冒号。 不过,考虑到马丁解决方案的其余部分是多么简单,我非常愿意接受它!


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

Or more generally, how do I remove an item from a colon-separated list in a Bash environment variable?

I thought I had seen a simple way to do this years ago, using the more advanced forms of Bash variable expansion, but if so I've lost track of it. A quick search of Google turned up surprisingly few relevant results and none that I would call "simple" or "elegant". For example, two methods using sed and awk, respectively:

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)

Does nothing straightforward exist? Is there anything analogous to a split() function in Bash?

Update:
It looks like I need to apologize for my intentionally-vague question; I was less interested in solving a specific use-case than in provoking good discussion. Fortunately, I got it!

There are some very clever techniques here. In the end, I've added the following three functions to my toolbox. The magic happens in path_remove, which is based largely on Martin York's clever use of awk's RS variable.

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/:$//'`; }

The only real cruft in there is the use of sed to remove the trailing colon. Considering how straightforward the rest of Martin's solution is, though, I'm quite willing to live with it!


Related question:How do I manipulate $PATH elements in shell scripts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

离笑几人歌 2024-07-18 02:53:35

我的肮脏黑客:

echo ${PATH} > t1
vi t1
export PATH=$(cat t1)

My dirty hack:

echo ${PATH} > t1
vi t1
export PATH=$(cat t1)
手长情犹 2024-07-18 02:53:35

用 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/:*$//')

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

A minute with awk:

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

Edit: It response to comments below:

$ 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!

Edit in response to security problem: (that is not relevant to the question)

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

This removes any trailing colons left by deleting the last entries, which would effectively add . to your path.

半边脸i 2024-07-18 02:53:35

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

# 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

纯粹的狂欢:)。

Since the big issue with substitution is the end cases, how about making the end cases no different to the other cases? If the path already had colons at the start and end, we could simply search for our desired string wrapped with colons. As it is, we can easily add those colons and remove them afterwards.

# 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

Pure bash :).

胡渣熟男 2024-07-18 02:53:35

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

#!/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

即使我认为$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[*]}"

Here's the simplest solution i can devise:

#!/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[*]}"

The above example will remove any element in $PATH that contains "usr". You can replace "*usr*" with "/home/user/bin" to remove just that element.

update per sschuberth

Even though i think spaces in a $PATH are a horrible idea, here's a solution that handles it:

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[*]}");

or

IFS=':'
t=($PATH)
n=${#t[*]}
a=()
for ((i=0;i<n;i++)); do
  p="${t[i]%%*usr*}"
  [ "${p}" ] && a[i]="${p}"
done
echo "${a[*]}"
静若繁花 2024-07-18 02:53:35

尽管当前已接受并且评分最高的答案,不会在PATH中添加不可见字符,并且可以应对包含空格的路径:

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

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

Here's a one-liner that, despite the current accepted and highest rated answers, does not add invisible characters to PATH and can cope with paths that contain spaces:

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

Personally, I also find this easy to read / understand, and it only involves common commands instead of using awk.

嘿看小鸭子会跑 2024-07-18 02:53:35

这是一个解决方案:

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

    removeFromPath() { 
         当地警察 
         p=":$1:" 
         d =“:$路径:” 
         d=${d//$p/:} 
         d=${d/#:/} 
         路径=${d/%:/} 
      }

Here is a solution that:

  • is pure Bash,
  • does not invoke other processes (like 'sed' or 'awk'),
  • does not change IFS,
  • does not fork a sub-shell,
  • handles paths with spaces, and
  • removes all occurrences of the argument in PATH.

    removeFromPath() {
       local p d
       p=":$1:"
       d=":$PATH:"
       d=${d//$p/:}
       d=${d/#:/}
       PATH=${d/%:/}
    }
胡大本事 2024-07-18 02:53:35

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

function path_remove {
  # Delete path by parts so we can never accidentally remove sub paths
  PATH=${PATH//":$1:"/":"} # delete any instances in the middle
  PATH=${PATH/#"$1:"/} # delete any instance at the beginning
  PATH=${PATH/%":$1"/} # delete any instance at the end
}

这是基于不太正确的答案如果超级用户上尚不存在,请将目录添加到 $PATH,修复评论中提到的问题。

显然,如果您不需要解释性注释,可以将其制成单行函数。

The best pure bash option I have found so far is the following:

function path_remove {
  # Delete path by parts so we can never accidentally remove sub paths
  PATH=${PATH//":$1:"/":"} # delete any instances in the middle
  PATH=${PATH/#"$1:"/} # delete any instance at the beginning
  PATH=${PATH/%":$1"/} # delete any instance at the end
}

This is based on the not quite correct answer to Add directory to $PATH if it's not already there over on Superuser, fixing issues mentioned in comments.

Obviously this can be made into a single line function if you don't want the explanatory comments.

囍孤女 2024-07-18 02:53:35

我刚刚使用了 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" <[email protected]>
#Message-Id: <[email protected]>
#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 <[email protected]>

#       @(#)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;:\$;;"`
}

I've just been using the functions in the bash distribution, that have been there apparently since 1991. These are still in the bash-docs package on Fedora, and used to be used in /etc/profile, but no more...

$ 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" <[email protected]>
#Message-Id: <[email protected]>
#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 <[email protected]>

#       @(#)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;:\$;;"`
}
咆哮 2024-07-18 02:53:35
function __path_remove(){  
    local D=":${PATH}:";  
    [ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
}  

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

function __path_remove(){  
    local D=":${PATH}:";  
    [ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
}  

Dug it out from my .bashrc file.
When you play around with PATH, and it gets lost, awk/sed/grep becomes unavailable :-)

小帐篷 2024-07-18 02:53:35

Linux from Scratch 在 /etc/profile 中定义了三个 Bash 函数:

# 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

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

Linux from Scratch defines three Bash functions in /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

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

猛虎独行 2024-07-18 02:53:35

我确实在此处写了答案 (也使用 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:

无论如何,对于同一问题以及一大堆有用的答案,请参阅 此处

I did write an answer to this here (using awk too). But i'm not sure that's what you are looking for? It at least looks clear to me what it does, instead of trying to fit into one line. For a simple one liner, though, that only removes stuff, i recommend

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

Replacing is

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

or (shorter but less readable)

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

Anyway, for the same question, and a whole lot of useful answers, see here.

瑾兮 2024-07-18 02:53:35

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

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

path_remove () { 导出 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))")"
}

What is the most elegant way to remove a path from the $PATH variable in Bash?

What's more elegant than awk?

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

Python! It's a more readable and maintainable solution, and it is easy to inspect to see that it's really doing what you want.

Say you want to remove the first path element?

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

(Instead of piping from echo, os.getenv['PATH'] would be a little shorter, and provided the same result as the above, but I'm worried that Python might do something with that environment variable, so it's probably best to pipe it directly from the environment you care about.)

Similarly to remove from the end:

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

To make these reusable shell functions that you can, for example, stick in your .bashrc file:

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))")"
}
聆听风音 2024-07-18 02:53:35

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

PATH=${PATH/:\/home\/user\/bin/}

Well, in bash, as it supports regular expression, I would simply do :

PATH=${PATH/:\/home\/user\/bin/}
智商已欠费 2024-07-18 02:53:35

我喜欢@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"

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

I like the three functions shown in @BenBlank's update to his original question. To generalize them, I use a 2-argument form, which allows me to set PATH or any other environment variable I want:

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/:$//'`"; }

Examples of use:

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

Note that I also added some quotation marks to allow for the proper processing of pathnames that contain spaces.

叫嚣ゝ 2024-07-18 02:53:35

使这个问题变得烦人的是第一个和最后一个元素之间的栅栏情况。 通过更改 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"

What makes this problem annoying are the fencepost cases among first and last elements. The problem can be elegantly solved by changing IFS and using an array, but I don't know how to re-introduce the colon once the path is converted to array form.

Here is a slightly less elegant version that removes one directory from $PATH using string manipulation only. I have tested it.

#!/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"
何以笙箫默 2024-07-18 02:53:35

是的,例如,在 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 

Yes, putting a colon at the end of PATH, for example, makes removing a path a bit less clumsy & error-prone.

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 
叫思念不要吵 2024-07-18 02:53:35

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

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

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

If you are concerned about removing duplicates in $PATH, the most elegant way, IMHO, would be not to add them in the first place. In 1 line:

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

$folder can be be replaced by anything, and may contain spaces ("/home/user/my documents")

寂寞美少年 2024-07-18 02:53:35

迄今为止我发现的最优雅的纯 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"                                  
} 

The most elegant pure bash solution I've found to date:

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"                                  
} 
一绘本一梦想 2024-07-18 02:53:35

大多数其他建议的解决方案仅依赖于字符串匹配,并且不考虑包含特殊名称的路径段,例如 ...~. 下面的 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'

Most of the other suggested solutions rely only on string matching and don't take into account path segments containing special names like ., .., or ~. The bash function below resolves directory strings in its argument and in path segments to find logical directory matches as well as string matches.

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}
}

Test:

$ 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'
别在捏我脸啦 2024-07-18 02:53:35

我知道这个问题询问的是 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

I know this question asks about BASH, which everyone should prefer, but since I enjoy symmetry and sometimes I'm required to use "csh", I built the equivalent to the "path_prepend()", "path_append()" and "path_remove()" elegant solution above.

The gist is that "csh" doesn't have functions, so I put little shell scripts in my personal bin directory that act like the functions. I create aliases to SOURCE those scripts to make the designated environment variable changes.

~/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'"
…

You can use them like this...

%(csh)> path_append MODULEPATH ${HOME}/modulefiles
热风软妹 2024-07-18 02:53:35

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

Bash built-in oneliner (doesn't remove repetition):
PATH=${PATH/${PATH/#$DIR:*/$DIR:}/}${PATH/${PATH/*:$DIR*/:$DIR}/}

葵雨 2024-07-18 02:53:35

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

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

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

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

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

最好的祝愿。

Since this tends to be quite problematic, as in there IS NO elegant way, I recommend avoiding the problem by rearranging the solution: build your PATH up rather than attempt to tear it down.

I could be more specific if I knew your real problem context. In the interim, I will use a software build as the context.

A common problem with software builds is that it breaks on some machines, ultimately due to how someone has configured their default shell (PATH and other environment variables). The elegant solution is to make your build scripts immune by fully specifying the shell environment. Code your build scripts to set the PATH and other environment variables based on assembling pieces that you control, such as the location of the compiler, libraries, tools, components, etc. Make each configurable item something that you can individually set, verify, and then use appropriately in your script.

For example, I have a Maven-based WebLogic-targeted Java build that I inherited at my new employer. The build script is notorious for being fragile, and another new employee and I spent three weeks (not full time, just here and there, but still many hours) getting it to work on our machines. An essential step was that I took control of the PATH so that I knew exactly which Java, which Maven, and which WebLogic was being invoked. I created environment variables to point to each of those tools, then I calculated the PATH based on those plus a few others. Similar techniques tamed the other configurable settings, until we finally created a reproducible build.

By the way, don't use Maven, Java is okay, and only buy WebLogic if you absolutely need its clustering (but otherwise no, and especially not its proprietary features).

Best wishes.

孤君无依 2024-07-18 02:53:35

与@litb一样,我对问题“How我是否在 shell 脚本中操作 $PATH 元素”,所以我的主要答案就在那里。

bash 和其他 Bourne shell 衍生产品中的“分割”功能是通过字段间分隔符 $IFS 完美实现的。 例如,要将位置参数 ($1, $2, ...) 设置为 PATH 的元素,请使用:

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

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

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

As with @litb, I contributed an answer to the question "How do I manipulate $PATH elements in shell scripts", so my main answer is there.

The 'split' functionality in bash and other Bourne shell derivatives is most neatly achieved with $IFS, the inter-field separator. For example, to set the positional arguments ($1, $2, ...) to the elements of PATH, use:

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

It will work OK as long as there are no spaces in $PATH. Making it work for path elements containing spaces is a non-trivial exercise - left for the interested reader. It is probably simpler to deal with it using a scripting language such as Perl.

I also have a script, clnpath, which I use extensively for setting my PATH. I documented it in the answer to "How to keep from duplicating PATH variable in csh".

美人迟暮 2024-07-18 02:53:35

这是一个 Perl 语句:

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

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

Here's a Perl one-liner:

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

The $a variable gets the path to be removed. The s (substitute) and print commands implicitly operate on the $_ variable.

⒈起吃苦の倖褔 2024-07-18 02:53:35

这里有好东西。
我使用这个是为了从一开始就避免添加欺骗。

#!/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

Good stuff here.
I use this one to keep from adding dupes in the first place.

#!/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
芯好空 2024-07-18 02:53:35

启用扩展通配符后,可以执行以下操作:

# 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

With extended globbing enabled it's possible to do the following:

# 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
清风夜微凉 2024-07-18 02:53:35

扩展的通配符单行(嗯,有点):

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; } 

Extended globbing one-liner (well, sort of):

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

There seems no need to escape slashes in $1.

path_remove ()  { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 
蔚蓝源自深海 2024-07-18 02:53:35

将冒号添加到 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 

Adding colons to PATH we could also do something like:

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 
徒留西风 2024-07-18 02:53:35

在path_remove_all中(由proxxy):

-newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" 
+newPATH="${newPATH//:${@:${i}:1}*([^:])/}"        # s/:\/path[^:]*//g 

In path_remove_all (by proxxy):

-newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" 
+newPATH="${newPATH//:${@:${i}:1}*([^:])/}"        # s/:\/path[^:]*//g 
放飞的风筝 2024-07-18 02:53:35

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

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

在这个 博客文章。 我想我最喜欢这个:)

While this is a very old thread, I thought this solution might be of interest:

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

found it on this blog post. I think I like this one most :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文