或者更一般地说,如何从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元素?
我的肮脏黑客:
echo ${PATH} > t1 vi t1 export PATH=$(cat t1)
与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/:*$//')
这将通过删除最后一个条目来删除任何尾随冒号,这将有效地添加.
到您的路径中.
由于替换的最大问题是最终案例,如何使最终案例与其他案例没有什么不同?如果路径在开始和结束时已经有冒号,我们可以简单地搜索用冒号包裹的所需字符串.事实上,我们可以轻松添加这些冒号并在之后删除它们.
# 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
纯粹的打击:).
这是我可以设计的最简单的解决方案:
#!/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要么
IFS=':' t=($PATH) n=${#t[*]} a=() for ((i=0;i
作为一个班轮:PATH = $(IFS =':'; t =($ PATH);未设置IFS; t =($ {t [@] %%*usr*}); IFS =':'; echo"$ {T [*]}");
5> sschuberth..:这是一个单线程,尽管当前接受和评级最高的答案,但不会向PATH添加不可见的字符,并且可以处理包含空格的路径:
export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:})就个人而言,我也发现这很容易阅读/理解,它只涉及常见命令而不是使用awk.
...如果你想要一些甚至可以应对文件名换行的东西,你可以使用它:`export PATH = $(p = $(echo $ PATH | tr":""\ 0"| grep -v -z "/ cygwin /"| tr"\ 0"":"); echo $ {p%:})`(尽管可以说,你可能想问问自己为什么需要这个,如果你这样做:))
6> 小智..:这是一个解决方案:
是纯粹的Bash,
不会调用其他进程(如'sed'或'awk'),
不改变
IFS
,不分叉子壳,
处理带空格的路径,和
删除所有出现的参数
PATH
.removeFromPath() { local p d p=":$1:" d=":$PATH:" d=${d//$p/:} d=${d/#:/} PATH=${d/%:/} }
我喜欢这个解决方案.也许让变量名更具描述性?
7> GreenFox..:function __path_remove(){
local D =":$ {PATH}:";
["$ {D /:$ 1:/:}"!="$ D"] && PATH ="$ {D /:$ 1:/:}";
PATH = "$ {PATH /#:/}";
export PATH ="$ {PATH /%:/}";
}从我的.bashrc文件中挖出来.当你玩PATH时,它会丢失,awk/sed/grep变得不可用:-)
8> Mark Booth..:到目前为止我发现的最好的纯bash选项如下:
function path_remove { PATH=${PATH/":$1"/} # delete any instances in the middle or at the end PATH=${PATH/"$1:"/} # delete any instances at the beginning }这是基于添加目录到$ PATH的不太正确的答案,如果它还没有超级用户.
9> 小智..:我一直在使用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"#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 # @(#)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;:\$;;"` }