根据正则表达式删除$ PATH条目

时间:2014-06-05 10:06:37

标签: regex perl shell replace

如果该条目包含给定字符串foo,我正在尝试删除$ PATH中的条目。例如,PATH=/home/me/bin:/home/foo/bin:/usr/foo/bin:/bin将成为PATH=/home/me/bin:/bin。我目前有

echo $PATH | perl -pe 's/:(.*?)foo(.*?):/:/g'

但这似乎删除了太多条目,即使我正在尝试使用非贪婪的匹配。我做错了什么?

5 个答案:

答案 0 :(得分:5)

我会分割字符串,选择有效部分,然后再次加入字符串:

perl -e 'print join ":", grep !/foo/, split ":", $ENV{PATH}'

答案 1 :(得分:1)

您可以使用:

perl -pe 's/:(.*?)foo[^:]*(?=:|$)//g' <<< "$PATH"
/home/me/bin:/bin

答案 2 :(得分:1)

您还可以使用awk遍历路径,只打印不包含foo的路径:

awk -F: '{for (i=1; i<=NF; i++) if ($i !~ /foo/) {printf "%s%s", $i, (i==NF? RS : FS)}}'

解释

  • -F::设置为字段分隔符。
  • for (i=1; i<=NF; i++)遍历字段。
  • if ($i !~ /foo/)如果路径不包含字符串foo,请执行下一步操作:
  • printf "%s%s", $i, (i==NF? RS : FS)打印该行,以新行或:结尾,具体取决于其位置。如果是最后一个字段,新行;否则,:

测试

$ cat a
/home/me/bin:/home/foo/bin:/usr/foo/bin:/bin
/home/me/bin:/home/fio/bin:/usr/foo/bin:/bin

$ awk -F: '{for (i=1; i<=NF; i++) if ($i !~ /foo/) {printf "%s%s", $i, (i==NF? RS : FS)}}' a
/home/me/bin:/bin
/home/me/bin:/home/fio/bin:/bin

答案 3 :(得分:0)

我开始构建一个正则表达式,它可以处理两端冒号的所有组合,但速度很快。但是既然你正在使用Perl(很好的选择BTW),那就是:

perl -e 'print join(":", grep { $_ !~ m/foo/ } split( ":", '"$PATH"' ) );'

答案 4 :(得分:0)

您可以在下面的正则表达式中使用非贪婪的匹配.*?

echo $PATH | perl -pe 's/:(.*?)foo(.*?):/:/g'

但是,正则表达式中存在一个缺陷,因为您没有限制允许的字符,因此它可以捕获整个冒号边界。

split是一个很好的工具的原因之一。它不仅强制执行边界,还强制它们之间接受的字符。

当然,使用正则表达式可以做到这一点,就像你想要的那样:

echo $PATH | perl -pe 's/[^:=]*foo[^:]*:?//g'

如果它是最后一个条目,则上面会留下一个尾随冒号。