我如何操纵$路元件壳脚本?
-
07-07-2019 - |
题
是否有一个习惯用的方式消除因素,从路径的状壳变量?
这就是我想要
PATH=/home/joe/bin:/usr/local/bin:/usr/bin:/bin:/path/to/app/bin:.
和 删除 或 替换 的 /path/to/app/bin
不会重装的其他变量。额外加分允许我 把 新的元素中的任意位置。目标将可识别的以及定义的字符串,并且可以发生在任何一点的清单。
我知道我看过这样做,并且也许可以拼凑的东西一起在我自己的,但是我在寻找一个很好的方法。便携性和标准化。
我使用的庆典,但例欢迎在你最喜欢的外壳。
这里的上下文中是一个需要开方便之间的多种版本(一个这样做的分析,另一个工作框架)的一个大型的科学分析软件包,其产生的几十个可执行,有数据的储藏周围的文件系统,并采用环境变量,以帮助找到所有这些东西。我想写的脚本中选择一个版本,和需要,以便能够删除 $PATH
有关当前活动的版本和替换他们的相同的要素有关的新版本。
这是有关该问题的防止重复 $PATH
元素时再行登脚本等。
- 以前类似的问题: 如何保持从复制的路径变量在csh
- 随后类似的问题: 什么是最优雅的方式,以去除的路径美元的路径变量庆典?
解决方案
解决所提出的解决方案,从dmckee:
- 虽然一些版本的Bash可以允许连字符的在职能名称,其他人(mac os X)不这样做。
- 我没有看到需要使立即返回之前端功能。
- 我没有看到需要为所有的半冒号。
- 我不明白为什么你有路元件的图案出口了价值。想想
export
为等同于设置(或甚至创建)全球变的东西,以尽可能避免。 - 我不知道什么是你期望的'
replace-path PATH $PATH /usr
'要做,但是它不会做什么我会的期望。
考虑一个路径的价值,开始了包含:
.
/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没有出现作为一(完成的)路元件,只有如路径的一部分元。
这可以是固定在 replace-path
通过修改之一 sed
命令:
export $path=$(echo -n $list | tr ":" "\n" | sed "s:^$removestr\$:$replacestr:" |
tr "\n" ":" | sed "s|::|:|g")
我用':'代替'|'到独立的部件的替代,因为'|'可以(在理论上)出现在一个道路组件,而通过的定义的道路,一个冒号。我注意到,第二 sed
可以消除当前的目录,从中间的一个路径。这是一个合法的(虽然不正当的)价值的路径可以是:
PATH=/bin::/usr/local/bin
在处理之后,当前的目录,将不再进的道路上。
一个类似的更改,以锚定匹配合适 path-element-by-pattern
:
export $target=$(echo -n $list | tr ":" "\n" | grep -m 1 "^$pat\$")
我注意到在通过, grep -m 1
不是标准(这是一个GNU扩展,也可在mac os 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
我找到有用的,当调试问题路-喜欢变量:
#!/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
它产生相同的输出。
其他提示
重新发布,我的答案 什么是最优雅的方式,以去除的路径美元的路径变量庆典? :
#!/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[*]}");
删除一个元素可以使用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" ":"
有一对夫妇的相关程序中的答案"如何保持从复制的路径变量在csh".他们更专注于确保没有重复的要素,但是在脚本我提供可用作:
export PATH=$(clnpath $head_dirs:$PATH:$tail_dirs $remove_dirs)
假设你已经一个或多个目录在$head_dirs和一个或多个目录在$tail_dirs和一个或多个目录在$remove_dirs,那么它利用外壳连接头部,当前和尾部分变成一个巨大的价值,然后删除的每一个目录列出的美元remove_dirs的结果(不是一个错误,如果它们不存在),以及作为消除第二次和随后出现的任何目录中的路径。
这个没有地址把路径成为一个特定的位置(除在开始或结束,和那些只是间接地).Notationally,指定要添加的新的因素,或者其元件你想要的更换,是混乱。
只是一个注意,庆典本身可以做的搜索和替换。它可以做所有的正常的"一次或所有",案[在]敏感的选项。
从人页:
${参数/模式/string}
该模式扩展到生产模式正如在路径的扩大。参数是扩大的和最长的匹配的模式对其价值的替换为与串。如果Ipattern开始与/所有匹配的模式被替换为与串。通常只有第一个比赛被替换。如果模式的开始#,它必须与在开始扩大价值的参数。如果模式开始%,它必须与在结束扩大的价值的参数。如果string is null,相匹配的模式是删除和/下列方式也可以省略。如果参数@或 *、替换操作应用于每个位置参数变,并膨胀为结果的列表。如果参数的一系列可变下标@或者 *、替代的操作应用到每个成员列反过来,并膨胀为结果的列表。
你也可以做场分裂通过设置$IFS(输入领域分离器)的所需隔符。
好的,感谢所有响应者。我已经准备了一封装版本的林的答复。第一遍是这样的:
# 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;
}
仍然需要错误捕获所有的功能,我可能应该坚持在重复路径解决方案的同时,我在这。
你用它做 . /include/path/path_tools.bash
在工作脚本,并呼吁的 replace-path*
功能。
我仍然打开新的和/或更好的答案。
这是容易使用awk.
替换
{
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
只是检查是否所有的元素都是路径,并得到返回代码,也可以使用 test
:
echo -n $PATH | xargs -d: -n1 test -d
假设
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
如果你想删除/lib/jvm/java-1.6.0/bin/不喜欢如下
export PATH=$(echo $PATH | sed 's/\/lib\/jvm\/java-1.6.0\/bin\/://g')
sed
将输入从 echo $PATH
和替换/lib/jvm/java-1.6.0/bin/:有空的
这样,你可以除去
- 秩序的道路是不distrubed
- 处理角情况下,像空空的道路,空间在正常的路径
- 部分匹配的dir不得误报
- 把路径在头部和尾部的路径以适当方式。没有 : 垃圾等。
说你有 /foo:/某些/path:/某些/path/dir1:/某些/path/dir2:/吧 你想要替换 /某些/path 然后它正确地将替换"/某些/路径",但是 叶"/某些/path/dir1"或"/某些/path/dir2",为什么你期望的。
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
}
我更喜欢使用红宝石的awk/sed/foo这些天来,因此,这里是我的办法来处理重复,
# 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(":")')
}
哈希阵列和串在一个红宝石的一个衬垫:)
第一件事要出入我的头变化只是部分的一串是一个sed替代。
例如:如果echo$PATH=>"/usr/件/bin:/usr/bin:/bin:/usr/件/游戏:/usr/件/X11R6/bin" 然后变化"/usr/bin",以"/usr/local/bin"可以做这样的:
##产生的标准输出的文件
##the"="字而不是使用斜线("/"),因为这将是混乱的 #替代引用字应该是不可能的路径
##路径separater角色":"这两个删除,并重新加入这里, #可能需要一个额外的结肠后的最后的路径
echo$PATH|sed'=/usr/bin:=/usr/local/bin:='
这个解决方案取代整个路径元所以可能是多余的,如果新的元素是类似的。
如果新的道路'-s不是动态的,但始终在一些常设你可以保存 那些 在一个变量和指定为需要:
PATH=$TEMP_PATH_1;#命令...; PATH=$TEMP_PATH_2;#命令,等等...;
可能不是你们的思维。一些相关的命令对bash/unix将是:
on popd cd ls#也许我-1A单列;找到 查询 这#能确认该文件是在那里你觉得它来自;env 类型
...和所有的和更多的有 一些 轴承,上路径或目录。该文本的改变的部分可以做任何数量的方式!
任何解决方案的选择会有4个部分:
1)取的路径,因为它是 2)解的路径,以找到一部分需要改变 3)确定什么变动需要的/整合的那些改变 4)校验/最终的一体化/定的变量
在线 dj_segfault的答案, 我做这个脚本中,追加/prepend环境变量,可能是执行多的时间:
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}}
使用这个同样的技术来清除、替换或处理中的项路径是微不足道的给定名膨胀状模式匹配和模式列表支持壳参数的膨胀。