【问题标题】:match multiple conditions with GNU sed使用 GNU sed 匹配多个条件
【发布时间】:2017-03-11 13:43:54
【问题描述】:

我正在使用 sed 替换其他 bash 脚本中的值,例如:

somedata="$(<somefile.sh)"
somedata=`sed 's/ ==/==/g' <<< $somedata` # [space]== becomes ==
somedata=`sed 's/== /==/g' <<< $somedata` # ==[space] becomes ==

||、&&、!= 等也是如此。我认为应该通过正确的正则表达式匹配来减少步骤。运算符不需要周围的空格,但可以在前后、仅在之前或仅在之后有空格。有没有办法用一个 sed 命令来处理所有这些问题?

还有很多其他的条件也没有提到。该脚本的执行时间比预期的要长。

目标是减少整体执行时间,因此我希望减少使用聪明的正则表达式匹配多个条件的命令数量。

我也在考虑 tr、awk 或 perl - 哪个最快?

【问题讨论】:

  • 在 bash 中,&amp;&amp;||==!= 周围允许有空格,那么为什么还要麻烦删除它们呢?
  • &amp; 表示替换右侧的the string that matched the regexp,因此您需要在该上下文中转义&amp;s。
  • @ThisSuitIsBlackNot 缩小脚本。
  • @EdMorton 感谢您指出这一点,我只是将其作为样本输入而没有进行测试。更新了问题。
  • 从左侧移除转义符。 &s 是捕获组参考字符,而不是正则表达式元字符。不要只是逃避您认为“特殊”的每个字符(因为软件中的任何内容都不应被视为“特殊”或“新” - 永远不要在描述软件功能时使用这两个词!)因为您可以通过这样做将它们变成元字符.了解每个字符在给定上下文中的含义,因为每个上下文中的含义都不同

标签: bash perl shell awk sed


【解决方案1】:

您可以使用 -e 标志链接多个 sed 替换:

$ echo -n "test data here" | sed -e 's/test/TEST/' \
                                 -e 's/data/HERE/' \ 
                                 -e 's/here/DATA/'
$ TEST HERE DATA

【讨论】:

    【解决方案2】:

    您可以使用sedfile-f 选项)和-i 选项(就地替换,无需存储在环境变量中):

    sed -i -f mysedfile somefile.sh
    

    mysedfile 可能包含表达式,每行 1 个

    s/ *&& */\&\&/g
    s/ *== */==/g
    

    (或者使用-e选项来使用多个表达式,但是如果你有很多,它会很快变得不可读)

    BTW:-i 选项在处理后的文件目录创建一个临时文件,所以最后,如果操作成功,原文件被删除,临时文件被重命名 /em> 改成原来的文件名

    当到达文件末尾时,临时文件被重命名 到输出文件的原始名称。扩展名(如果提供), 用于在重命名之前修改旧文件的名称 临时文件,从而制作备份副本(2))

    所以该选项没有 I/O 开销。根本不需要存储在变量中。

    【讨论】:

    • 我有意将数据存储在一个变量中,以减少与 -i 内联选项有关的所有文件读/写和 tmp 文件创建的执行时间。 sed 文件或 -e 选项是否仍会执行多个子进程?目标是通过使用更少命令的巧妙正则表达式来减少执行时间。
    • 多个-e 选项不会调用多个进程,这是等效的。并查看我对 -i 选项的编辑。
    • 是的,但是会创建一个临时文件,对其进行读写,删除原始文件,并重命名临时文件。与读取文件相比,一切都在内存中完成,文件被写入。另请注意,变量是函数中的局部变量。
    【解决方案3】:

    使用 GNU sed,您可以使用 |(或)运算符:

    $ sed -r 's/ *(&&|\|\|) */\1/g' <<< "foo && bar || baz"
    foo&&bar||baz
    
    • *(&amp;&amp;|\|\|) *:搜索零个或多个空格,后跟任何 | 分隔字符串,后跟零个或多个空格
    • 使用反向引用捕获和输出匹配的字符串

    编辑:

    正如 cmets 中所指出的,您可以在 GNU sed 中使用 -E 标志来代替 -r。您的命令将更便携:

    sed -E 's/ *(\&\&|\|\|) */\1/g'
    

    由于 GNU sed 还支持带有基本正则表达式的 \| 交替运算符,您可以使用它来提高可读性:

    sed 's/ *\(&&\|||\) */\1/g'
    

    【讨论】:

    • 啊,是的,反向引用将来会对我有很大帮助,谢谢
    • 如果你摆脱了-r(无论如何你都不应该使用它,如果你需要在这种情况下不需要的ERE,请使用-E来代替可移植性),那么你可以获得摆脱 &amp;| 字符的转义,您所要做的就是转义捕获组分隔符,您就有了一个更简洁、可移植的脚本。
    • @EdMorton BRE 不包括交替运算符(转义的 \| 是 GNU sed 扩展)。我不确定在 BRE 模式下使用这个操作符会不会更便携。
    • 我明白你在说什么,我错过了你需要| 元字符。不过,我不确定是否只是 GNU sed 支持启用带有转义的 ERE 元字符,-E 肯定会在多个 sed 版本中启用 ERE,而-r 仅对 GNU sed 启用。
    猜你喜欢
    • 2021-05-13
    • 2023-03-13
    • 2021-12-11
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多