Unix 如何在shell脚本中操作$PATH元素?

Unix 如何在shell脚本中操作$PATH元素?,unix,shell,idioms,path-variables,Unix,Shell,Idioms,Path Variables,有没有一种惯用的方法可以从类似路径的shell变量中删除元素 这就是我想要的 PATH=/home/joe/bin:/usr/local/bin:/usr/bin:/bin:/path/to/app/bin:. 和删除或替换/path/to/app/bin,而不破坏变量的其余部分。允许我在任意位置放置新元素的额外点。目标将由定义良好的字符串识别,并且可能出现在列表中的任何点 我知道我已经看到了这一点,也许我可以自己拼凑一些东西,但我正在寻找一个很好的方法。可移植性和标准化优先 我使用bash,

有没有一种惯用的方法可以从类似路径的shell变量中删除元素

这就是我想要的

PATH=/home/joe/bin:/usr/local/bin:/usr/bin:/bin:/path/to/app/bin:.
删除替换
/path/to/app/bin
,而不破坏变量的其余部分。允许我在任意位置放置新元素的额外点。目标将由定义良好的字符串识别,并且可能出现在列表中的任何点

我知道我已经看到了这一点,也许我可以自己拼凑一些东西,但我正在寻找一个很好的方法。可移植性和标准化优先

我使用bash,但在您最喜欢的shell中也欢迎使用示例


这里的上下文是需要在一个大型科学分析包的多个版本(一个用于分析,另一个用于处理框架)之间方便地切换,该分析包生成几十个可执行文件,在文件系统中存储数据,并使用环境变量帮助查找所有这些内容。我想编写一个脚本来选择一个版本,并且需要能够删除与当前活动版本相关的
$PATH
元素,并用与新版本相关的相同元素替换它们


这与在重新运行登录脚本等时防止重复的
$PATH
元素有关


  • 先前的类似问题:
  • 随后的类似问题:

要删除元素,可以使用sed:

#!/bin/bash
NEW_PATH=$(echo -n $PATH | tr ":" "\n" | sed "/foo/d" | tr "\n" ":")
export PATH=$NEW_PATH
将从路径中删除包含“foo”的路径

您还可以使用sed在给定行之前或之后插入新行

编辑:可以通过排序和uniq管道删除重复项:

echo -n $PATH | tr ":" "\n" | sort | uniq -c | sed -n "/ 1 / s/.*1 \(.*\)/\1/p" | sed "/foo/d" | tr "\n" ":"

第一件突然出现在我脑海中改变字符串的一部分的事情是sed替换

例如: 如果echo$PATH=>“/usr/pkg/bin:/usr/bin:/bin:/usr/pkg/games:/usr/pkg/X11R6/bin” 然后将“/usr/bin”更改为“/usr/local/bin”可以这样做:

# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
#    replace-path         PATH $PATH /exact/path/to/remove    
#    replace-path-pattern PATH $PATH <grep pattern for target path>    
#
# To replace a path:
#    replace-path         PATH $PATH /exact/path/to/remove /replacement/path   
#    replace-path-pattern PATH $PATH <target pattern> /replacement/path
#    
###############################################################################
# Finds the _first_ list element matching $2
#
#    $1 name of a shell variable to be set
#    $2 name of a variable with a path-like structure
#    $3 a grep pattern to match the desired element of $1
function path-element-by-pattern (){ 
    target=$1;
    list=$2;
    pat=$3;

    export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 $pat);
    return
}

# Removes or replaces an element of $1
#
#   $1 name of the shell variable to set (i.e. PATH) 
#   $2 a ":" delimited list to work from (i.e. $PATH)
#   $2 the precise string to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace-path () {
    path=$1;
    list=$2;
    removestr=$3;
    replacestr=$4; # Allowed to be ""

    export $path=$(echo -n $list | tr ":" "\n" | sed "s|$removestr|$replacestr|" | tr "\n" ":" | sed "s|::|:|g");
    unset removestr
    return 
}

# Removes or replaces an element of $1
#
#   $1 name of the shell variable to set (i.e. PATH) 
#   $2 a ":" delimited list to work from (i.e. $PATH)
#   $2 a grep pattern identifying the element to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace-path-pattern () {
    path=$1;
    list=$2;
    removepat=$3; 
    replacestr=$4; # Allowed to be ""

    path-element-by-pattern removestr $list $removepat;
    replace-path $path $list $removestr $replacestr;
}
echo $PATH | awk -F: -f rem_dup.awk | paste -sd:
##生成标准输出文件

##使用“=”字符代替斜杠(“/”),因为这样会很混乱, #路径中不可能有替代引用字符

##路径分隔符“:”在此处被删除并重新添加, #在最后一个路径后可能需要额外的冒号

echo$PATH | sed'=/usr/bin:=/usr/local/bin:='

此解决方案替换整个path元素,所以若新元素相似,则可能是多余的

如果新路径'-s不是动态的,但始终在某个常量集内,则可以将其保存在变量中,并根据需要分配:

路径=$TEMP_PATH_1; #命令\N 路径=$TEMP_PATH_2; #命令等

可能不是你想的那样。bash/unix上的一些相关命令是:

推动 邻苯二胺 光盘 对于单柱,ls#可能为l-1A; 找到 格雷普 这可以证实你认为文件是从哪里来的; 环境 类型

..所有这些和更多都对路径或目录有一些影响。文本更改部分可以通过多种方式完成

选择的任何解决方案都有4个部分:

1) 按原样获取路径 2) 解码路径以找到需要更改的零件 3) 确定需要哪些变更/整合这些变更
4) 验证/最终积分/设置变量

在对“”的回答中有两个相关程序。他们更专注于确保没有重复的元素,但我提供的脚本可以用作:

export PATH=$(clnpath $head_dirs:$PATH:$tail_dirs $remove_dirs)
假设$head\u dirs中有一个或多个目录,$tail\u dirs中有一个或多个目录,$remove\u dirs中有一个或多个目录,那么它使用shell将head、current和tail部分连接成一个大值,然后从结果中删除$remove\u dirs中列出的每个目录(如果不存在,则不是错误),以及消除路径中任何目录的第二次和后续出现


这不涉及将路径组件放置到特定位置(除了在开始或结束位置,以及仅间接放置的位置)。注意,指定要添加新元素的位置或要替换的元素很麻烦。

好的,感谢所有响应者。我已经准备了florin答案的封装版本。第一步如下所示:

# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
#    replace-path         PATH $PATH /exact/path/to/remove    
#    replace-path-pattern PATH $PATH <grep pattern for target path>    
#
# To replace a path:
#    replace-path         PATH $PATH /exact/path/to/remove /replacement/path   
#    replace-path-pattern PATH $PATH <target pattern> /replacement/path
#    
###############################################################################
# Finds the _first_ list element matching $2
#
#    $1 name of a shell variable to be set
#    $2 name of a variable with a path-like structure
#    $3 a grep pattern to match the desired element of $1
function path-element-by-pattern (){ 
    target=$1;
    list=$2;
    pat=$3;

    export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 $pat);
    return
}

# Removes or replaces an element of $1
#
#   $1 name of the shell variable to set (i.e. PATH) 
#   $2 a ":" delimited list to work from (i.e. $PATH)
#   $2 the precise string to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace-path () {
    path=$1;
    list=$2;
    removestr=$3;
    replacestr=$4; # Allowed to be ""

    export $path=$(echo -n $list | tr ":" "\n" | sed "s|$removestr|$replacestr|" | tr "\n" ":" | sed "s|::|:|g");
    unset removestr
    return 
}

# Removes or replaces an element of $1
#
#   $1 name of the shell variable to set (i.e. PATH) 
#   $2 a ":" delimited list to work from (i.e. $PATH)
#   $2 a grep pattern identifying the element to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace-path-pattern () {
    path=$1;
    list=$2;
    removepat=$3; 
    replacestr=$4; # Allowed to be ""

    path-element-by-pattern removestr $list $removepat;
    replace-path $path $list $removestr $replacestr;
}
echo $PATH | awk -F: -f rem_dup.awk | paste -sd:
#path_tools.bash
#
#一组用于操作“:”分隔列表的工具,如
#规范$PATH变量。
#
#/bin/sh可以通过替换$()重新获得兼容性
#使用``样式设置命令扩展的样式
###############################################################################
#用法:
#
#要删除路径,请执行以下操作:
#替换路径路径$path/exact/path/to/remove
#替换路径模式path$path
#
#要替换路径,请执行以下操作:
#替换路径路径$path/exact/path/to/remove/replacement/path
#替换路径模式路径$path/replacement/path
#    
###############################################################################
#查找与$2匹配的_first_uu列表元素
#
#$1要设置的shell变量的名称
#$2具有类似路径结构的变量的名称
#$3匹配所需元素$1的grep模式
模式()的函数路径元素{
目标=1美元;
名单=$2;
pat=3美元;
export$target=$(echo-n$list | tr:“\n”| grep-m1$pat);
返回
}
#删除或替换$1的元素
#
#$1要设置的shell变量的名称(即路径)
#$2A“:”要从中工作的分隔列表(即$PATH)
#$2要移除/替换的精确字符串
#$3替换字符串(使用“”删除)
函数替换路径(){
路径=$1;
名单=$2;
Removest=3美元;
replacestr=$4;#允许为“”
export$path=$(echo-n$list | tr:“\n”sed“s”|$removestr |$replacestr |“| tr”\n:“| sed”s |:::|:| g”);
未设定再投资
返回
}
#删除或替换$1的元素
#
#$1外壳的名称
PATH=/bin::/usr/local/bin
export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 "^$pat\$")
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
#    replace_path         PATH $PATH /exact/path/to/remove
#    replace_path_pattern PATH $PATH <grep pattern for target path>
#
# To replace a path:
#    replace_path         PATH $PATH /exact/path/to/remove /replacement/path
#    replace_path_pattern PATH $PATH <target pattern> /replacement/path
#
###############################################################################

# Remove or replace an element of $1
#
#   $1 name of the shell variable to set (e.g. PATH)
#   $2 a ":" delimited list to work from (e.g. $PATH)
#   $3 the precise string to be removed/replaced
#   $4 the replacement string (use "" for removal)
function replace_path () {
    path=$1
    list=$2
    remove=$3
    replace=$4        # Allowed to be empty or unset

    export $path=$(echo "$list" | tr ":" "\n" | sed "s:^$remove\$:$replace:" |
                   tr "\n" ":" | sed 's|:$||')
}

# Remove or replace an element of $1
#
#   $1 name of the shell variable to set (e.g. PATH)
#   $2 a ":" delimited list to work from (e.g. $PATH)
#   $3 a grep pattern identifying the element to be removed/replaced
#   $4 the replacement string (use "" for removal)
function replace_path_pattern () {
    path=$1
    list=$2
    removepat=$3
    replacestr=$4        # Allowed to be empty or unset

    removestr=$(echo "$list" | tr ":" "\n" | grep -m 1 "^$removepat\$")
    replace_path "$path" "$list" "$removestr" "$replacestr"
}
#!/usr/bin/perl -w
#
#   "@(#)$Id: echopath.pl,v 1.7 1998/09/15 03:16:36 jleffler Exp $"
#
#   Print the components of a PATH variable one per line.
#   If there are no colons in the arguments, assume that they are
#   the names of environment variables.

@ARGV = $ENV{PATH} unless @ARGV;

foreach $arg (@ARGV)
{
    $var = $arg;
    $var = $ENV{$arg} if $arg =~ /^[A-Za-z_][A-Za-z_0-9]*$/;
    $var = $arg unless $var;
    @lst = split /:/, $var;
    foreach $val (@lst)
    {
            print "$val\n";
    }
}
echo
xpath=$PATH
replace_path xpath $xpath /usr
echopath $xpath

echo
xpath=$PATH
replace_path_pattern xpath $xpath /usr/bin /work/bin
echopath xpath

echo
xpath=$PATH
replace_path_pattern xpath $xpath "/usr/.*/bin" /work/bin
echopath xpath
.
/Users/jleffler/bin
/usr/local/postgresql/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/usr/bin
/bin
/sw/bin
/usr/sbin
/sbin

.
/Users/jleffler/bin
/usr/local/postgresql/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/work/bin
/bin
/sw/bin
/usr/sbin
/sbin

.
/Users/jleffler/bin
/work/bin
/usr/local/mysql/bin
/Users/jleffler/perl/v5.10.0/bin
/usr/local/bin
/usr/bin
/bin
/sw/bin
/usr/sbin
/sbin
replace_path PATH /usr/bin /work/bin
list=$(eval echo '$'$path)
# path_tools.bash
#
# A set of tools for manipulating ":" separated lists like the
# canonical $PATH variable.
#
# /bin/sh compatibility can probably be regained by replacing $( )
# style command expansion with ` ` style
###############################################################################
# Usage:
#
# To remove a path:
#    replace_path         PATH /exact/path/to/remove
#    replace_path_pattern PATH <grep pattern for target path>
#
# To replace a path:
#    replace_path         PATH /exact/path/to/remove /replacement/path
#    replace_path_pattern PATH <target pattern> /replacement/path
#
###############################################################################

# Remove or replace an element of $1
#
#   $1 name of the shell variable to set (e.g. PATH)
#   $2 the precise string to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace_path () {
    path=$1
    list=$(eval echo '$'$path)
    remove=$2
    replace=$3            # Allowed to be empty or unset

    export $path=$(echo "$list" | tr ":" "\n" | sed "s:^$remove\$:$replace:" |
                   tr "\n" ":" | sed 's|:$||')
}

# Remove or replace an element of $1
#
#   $1 name of the shell variable to set (e.g. PATH)
#   $2 a grep pattern identifying the element to be removed/replaced
#   $3 the replacement string (use "" for removal)
function replace_path_pattern () {
    path=$1
    list=$(eval echo '$'$path)
    removepat=$2
    replacestr=$3            # Allowed to be empty or unset

    removestr=$(echo "$list" | tr ":" "\n" | grep -m 1 "^$removepat\$")
    replace_path "$path" "$removestr" "$replacestr"
}
echo
xpath=$PATH
replace_path xpath /usr
echopath xpath

echo
xpath=$PATH
replace_path_pattern xpath /usr/bin /work/bin
echopath xpath

echo
xpath=$PATH
replace_path_pattern xpath "/usr/.*/bin" /work/bin
echopath xpath
{
  for(i=1;i<=NF;i++) 
      if($i == REM) 
          if(REP)
              print REP; 
          else
              continue;
      else 
          print $i; 
}
function path_repl {
    echo $PATH | awk -F: -f rem.awk REM="$1" REP="$2" | paste -sd:
}

$ echo $PATH
/bin:/usr/bin:/home/js/usr/bin
$ path_repl /bin /baz
/baz:/usr/bin:/home/js/usr/bin
$ path_repl /bin
/usr/bin:/home/js/usr/bin
{ 
    if(IDX < 1) IDX = NF + IDX + 1
    for(i = 1; i <= NF; i++) {
        if(IDX == i) 
            print REP 
        print $i
    }
    if(IDX == NF + 1)
        print REP
}
function path_app {
    echo $PATH | awk -F: -f app.awk REP="$1" IDX="$2" | paste -sd:
}

$ echo $PATH
/bin:/usr/bin:/home/js/usr/bin
$ path_app /baz 0
/bin:/usr/bin:/home/js/usr/bin:/baz
$ path_app /baz -1
/bin:/usr/bin:/baz:/home/js/usr/bin
$ path_app /baz 1
/baz:/bin:/usr/bin:/home/js/usr/bin
{ 
    for(i = 1; i <= NF; i++) {
        if(!used[$i]) {
            print $i
            used[$i] = 1
        }
    }
}
echo $PATH | awk -F: -f rem_dup.awk | paste -sd:
echo -n $PATH | xargs -d: stat -c %n
echo -n $PATH | xargs -d: -n1 test -d
#!/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=$(IFS=':';t=($PATH);unset IFS;t=(${t[@]%%*usr*});IFS=':';echo "${t[*]}");
echo $PATH
/usr/lib/jvm/java-1.6.0/bin:lib/jvm/java-1.6.0/bin/:/lib/jvm/java-1.6.0/bin/:/usr/lib/qt-3.3/bin:/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/tvnadeesh/bin
export PATH=$(echo $PATH | sed  's/\/lib\/jvm\/java-1.6.0\/bin\/://g')
function __path_add(){  
    if [ -d "$1" ] ; then  
        local D=":${PATH}:";   
        [ "${D/:$1:/:}" == "$D" ] && PATH="$PATH:$1";  
        PATH="${PATH/#:/}";  
        export PATH="${PATH/%:/}";  
    fi  
}
function __path_remove(){  
    local D=":${PATH}:";  
    [ "${D/:$1:/:}" != "$D" ] && PATH="${D/:$1:/:}";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
}  
# Just for the shake of completeness
function __path_replace(){  
    if [ -d "$2" ] ; then  
        local D=":${PATH}:";   
        if [ "${D/:$1:/:}" != "$D" ] ; then
            PATH="${D/:$1:/:$2:}";  
            PATH="${PATH/#:/}";  
            export PATH="${PATH/%:/}";  
        fi
    fi  
}  
ld_library_path=${ORACLE_HOME}/lib
LD_LIBRARY_PATH=${LD_LIBRARY_PATH//${ld_library_path}?(:)/}
export LD_LIBRARY_PATH=${ld_library_path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
# add it to the path
PATH=~/bin/:$PATH:~/bin
export PATH=$(ruby -e 'puts ENV["PATH"].split(/:/).uniq.join(":")')
mungepath() {
   export PATH=$(ruby -e 'puts ENV["PATH"].split(/:/).uniq.join(":")')
}