【问题标题】:Remove $PATH entry based on regex删除基于正则表达式的 $PATH 条目
【发布时间】:2014-07-26 06:33:54
【问题描述】:

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

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

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

【问题讨论】:

  • 至于贪婪:那个正则表达式仍然会匹配 第一个 :,然后是直到foo。在这种情况下,非贪婪仅意味着它不会匹配途中的任何foos。您可能希望将 (.*?) 更改为 [^:]* 以明确不包含任何冒号(不确定捕获组的用途)。
  • ...此外,如果 foo 条目是第一个或最后一个(前后没有冒号),则该正则表达式将不起作用。在任一侧只使用[^:]* 应该可以解决这个问题。

标签: regex perl shell replace


【解决方案1】:

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

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

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

这就是为什么split 是一个不错的工具的原因之一。它不仅强制边界,而且强制它们之间的可接受字符。

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

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

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

【讨论】:

    【解决方案2】:

    您也可以使用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&lt;=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
    

    【讨论】:

    • 知道反对票的原因会很有趣。请随意解释,以便我检查一些不准确之处。
    • 不管怎样,awk 命令对我来说工作得很好,你为那些好奇的人提供了详细的解释。来自我的 +1。
    【解决方案3】:

    我开始构建一个正则表达式来处理两端冒号的所有组合,但它很快就变得复杂了。但是,既然您使用的是 Perl(顺便说一句,不错的选择),那么如何:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        你可以使用:

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

        【讨论】:

        • 这仍然会错误地删除条目。另外,出于兴趣,左三人字形是做什么的?
        • 这会删除 2 个包含 foo 的路径,为什么会出错,您的预期输出是什么?
        • 我的实际路径有点长,当我尝试你的正则表达式时,它仍然删除了匹配条目之前的一些条目。
        • 它使用提供的数据。如果在某些情况下不起作用,请提供输入数据和您的预期输出,我会调查。
        • 作为一个没有经验但想学习的正则表达式用户:?=: 是做什么的?
        猜你喜欢
        • 2017-11-24
        • 1970-01-01
        • 2020-10-16
        • 2011-05-14
        • 1970-01-01
        • 2019-02-16
        • 1970-01-01
        • 1970-01-01
        • 2018-02-28
        相关资源
        最近更新 更多