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

前端之家收集整理的这篇文章主要介绍了unix – 如何在shell脚本中操作$PATH元素?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
有没有一种惯用的方法从PATH类shell变量中删除元素?

这就是我想要的

PATH=/home/joe/bin:/usr/local/bin:/usr/bin:/bin:/path/to/app/bin:.

删除或替换/ path / to / app / bin,而不会破坏其余的变量。额外的点,让我把新元素在任意位置。目标将可以由明确定义的字符串识别,并且可以发生在列表中的任何点。

我知道我已经看到这一切,并可能在一起我自己的东西,但我正在寻找一个不错的方法。可移植性和标准化一加。

我使用bash,但例子是欢迎在你最喜欢的shell以及。

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

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

>上一个类似问题:How to keep from duplicating path variable in csh
>后续类似问题:What is the most elegant way to remove a path from the $PATH variable in Bash?

从dmckee解决建议的解决方案:

>虽然一些版本的Bash可能允许在函数名称中使用连字符,但其他(MacOS X)不能。
>我没有看到需要在函数结束之前立即使用返回。
>我没有看到所有的分号的需要。
>我不明白为什么你有path-element-by-pattern导出一个值。想想导出等同于设置(甚至创建)一个全局变量 – 尽可能避免的东西。
>我不知道你期望什么’replace-path PATH $ PATH / usr’,但它不会做我所期望的。

考虑一个PATH值开始包含:

.
/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

我得到的结果(从’replace-path PATH $ PATH / usr’)是:

.
/Users/jleffler/bin
/local/postgresql/bin
/local/MysqL/bin
/Users/jleffler/perl/v5.10.0/bin
/local/bin
/bin
/bin
/sw/bin
/sbin
/sbin

我希望得到我的原始路径,因为/ usr不显示为(完整)路径元素,只作为路径元素的一部分。

这可以通过修改sed命令之一在replace-path中修复:

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

我使用’:’而不是’|’以分隔替换的部分,因为’|’可以(在理论上)出现在路径组件中,而根据PATH的定义,冒号不能。我观察到第二个sed可以从PATH的中间消除当前目录。也就是说,PATH的合法(尽管有害)值可以是:

PATH=/bin::/usr/local/bin

处理后,当前目录将不再在PATH上。

锚定匹配的类似改变在路径逐个模式是适当的:

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

我注意到传递grep -m 1不是标准(它是一个GNU扩展,也可在MacOS X)。而且,确实,回声的-n选项也是非标准的;你最好只是删除通过将换行符从echo转换为冒号而添加的结尾冒号。由于路径元素一个模式只使用一次,具有不良的副作用(它破坏任何预先存在的导出变量$ removestr),它可以被它的身体明智地替换。这,以及更自由地使用引号以避免空格或不需要的文件名扩展的问题,导致:

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

我有一个Perl脚本echopath,我发现在调试问题类似PATH的变量时很有用:

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

这看起来对我是正确的 – 至少,对于我的定义的问题是什么。

我注意到echopath LD_LIBRARY_PATH评估$ LD_LIBRARY_PATH。这将是很好,如果你的功能能够做到这一点,所以用户可以键入:

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

它产生与以前相同的输出

原文链接:https://www.f2er.com/bash/389191.html

猜你在找的Bash相关文章