代码之家  ›  专栏  ›  技术社区  ›  Ben Blank Jarret Hardie

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

  •  134
  • Ben Blank Jarret Hardie  · 技术社区  · 16 年前

    或者更一般地说,如何从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 移除尾部结肠。不过,考虑到马丁的其余解决方案是多么简单,我非常愿意接受它!


    相关问题: How do I manipulate $PATH elements in shell scripts?

    34 回复  |  直到 16 年前
        1
  •  62
  •   Loki Astari    9 年前

    我的肮脏的黑客:

    echo ${PATH} > t1
    vi t1
    export PATH=$(cat t1)
    
        2
  •  57
  •   Danica MrDrFenner    9 年前

    一分钟与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/:*$//')
    

    这将删除最后一个条目留下的任何尾随冒号,这将有效地添加 . 走你的路。

        3
  •  47
  •   Andrew Aylett    11 年前

    既然替代的大问题是最终案例,那么让最终案例与其他案例没有区别怎么样?如果路径的开头和结尾已经有冒号,我们可以简单地搜索用冒号包裹的所需字符串。事实上,我们可以很容易地添加这些冒号并在之后删除它们。

    # 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:)。

        4
  •  27
  •   Community CDub    8 年前

    以下是我能想到的最简单的解决方案:

    #!/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 是a 令人恐惧的 idea,这里有一个处理它的解决方案:

    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[*]}"
    
        5
  •  13
  •   Community CDub    8 年前

    这是一条单行线,尽管水流湍急 accepted highest rated 答案,不会向PATH添加不可见字符,并且可以处理包含空格的路径:

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

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

        6
  •  9
  •   robinbb    10 年前

    以下是一个解决方案:

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

      removeFromPath() {
         local p d
         p=":$1:"
         d=":$PATH:"
         d=${d//$p/:}
         d=${d/#:/}
         PATH=${d/%:/}
      }
        7
  •  6
  •   GreenFox    13 年前

    我刚刚开始使用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;:\$;;"`
    }
    
        8
  •  6
  •   Community CDub    8 年前
    function __path_remove(){  
        local D=":${PATH}:";  
        [ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";  
        PATH="${PATH/#:/}";  
        export PATH="${PATH/%:/}";  
    }  
    

    从我的.bashrc文件中把它挖出来。 当你使用PATH时,如果它丢失了,awk/sed/grep将不可用:-)

        9
  •  5
  •   Mr. Wacky    13 年前

    到目前为止,我找到的最好的纯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
    }
    

    这是基于 not quite correct answer Add directory to $PATH if it's not already there 在Superuser上,修复了评论中提到的问题。

    显然,如果你不想要解释性注释,这可以做成一个单行函数。

        10
  •  4
  •   Community CDub    8 年前

    Linux from Scratch定义了三个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

        11
  •  3
  •   mat    16 年前

    好吧,在bash中,由于它支持正则表达式,我会简单地这样做:

    PATH=${PATH/:\/home\/user\/bin/}
    
        12
  •  2
  •   Cary Millsap    9 年前

    我确实写了一个答案 here (也使用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:
    

    不管怎样,对于同一个问题和许多有用的答案,请参阅 here .

        13
  •  2
  •   Aaron Hall    8 年前

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

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

        14
  •  1
  •   cyrill    15 年前

    在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))")"
    }
    
        15
  •  1
  •   MestreLion    14 年前

    是的,例如,在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 
    
        16
  •  1
  •   TriangleTodd    13 年前

    如果您担心删除 副本 在$PATH中,依我之见,最优雅的方式是一开始就不添加它们。1行:

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

    $文件夹可以被任何东西替换,并且可能包含空格(“/home/user/my documents”)

        17
  •  1
  •   jwfearn    10 年前

    我迄今为止发现的最优雅的纯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"                                  
    } 
    
        18
  •  1
  •   kevinarpe Dario Hamidi    9 年前

    大多数其他建议的解决方案只依赖于字符串匹配,不考虑包含特殊名称的路径段,如 . , .. ,或 ~ 。下面的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'
    
        19
  •  1
  •   Lance E.T. Compte    7 年前

    我知道这个问题问的是BASH,每个人都应该更喜欢它,但由于我喜欢对称性,有时我需要使用“csh”,我构建了与上面的“path_prepend()”、“path_append()”和“path_remove()”优雅解决方案等效的解决方案。

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

    ~/bin/_path_remove.sch:

    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
    
        20
  •  0
  •   Rob Williams    16 年前

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

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

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

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

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

    最美好的祝福。

        21
  •  0
  •   Community CDub    8 年前

    与@litb一样,我为这个问题提供了答案 How do I manipulate $PATH elements in shell scripts “所以我的主要答案就在那里。

    中的“拆分”功能 bash 其他Bourne shell衍生物最巧妙地实现了 $IFS ,场间分隔符。例如,要设置位置参数( $1 , $2 , ...)对于PATH的元素,使用:

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

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

    我也有一个剧本, clnpath ,我广泛使用它来设置我的PATH。我在回答“ How to keep from duplicating PATH variable in csh ".

        22
  •  0
  •   Norman Ramsey    16 年前

    让这个问题令人恼火的是第一个和最后一个元素之间的围栏案例。通过更改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"
    
        23
  •  0
  •   J. A. Faucett    16 年前

    这是一个Perl单行代码:

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

    这个 $a 变量获取要删除的路径。这个 s (替代)以及 print 命令隐式操作 $_ 变量。

        24
  •  0
  •   ongoto    15 年前

    这里有好东西。 我用这个来防止一开始就添加欺骗。

    #!/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
    
        25
  •  0
  •   carlo    15 年前

    启用扩展全局搜索后,可以执行以下操作:

    # 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
    
        26
  •  0
  •   carlo    15 年前

    加长球形内衬(嗯,有点):

    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; } 
    
        27
  •  0
  •   proxxy    15 年前

    在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 
    
        28
  •  0
  •   marius    15 年前

    在path_remove_all(通过proxxy)中:

    -newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" 
    +newPATH="${newPATH//:${@:${i}:1}*([^:])/}"        # s/:\/path[^:]*//g 
    
        29
  •  0
  •   mjc    14 年前

    虽然这是一个非常古老的话题,但我认为这个解决方案可能会引起人们的兴趣:

    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
    

    在这上面找到的 blog post 。我想我最喜欢这个:)

        30
  •  0
  •   jimeh    13 年前

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

    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_before path_add_after 允许您在path中的指定路径之前/之后插入路径。

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

    推荐文章