在 sed 中使用管道(或)

Using a pipe (or) in sed

来自包含类似

的变量$(JS_SOURCES)
"    thing.js myapp.mod1.js otherthing.js myapp.mod1.submod.js myapp.othermodule.js   "

make 写入包含 mod1,othermodule.

的文件

它适用于此代码:

./build/modules.txt: $(JS_SOURCES)
    @echo "$(JS_SOURCES)" | sed -r -e 's/\s\S*myapp\.(\w+)\.js\b/ /g' -e 's/\S*\.\S*//g' -e 's/^\s+//' -e 's/\s+$$//' -e 's/\b\s+\b/,/g' > $@

我的问题是为什么我不能替换 3 个表达式

-e 's/\S*\.\S*//g' -e 's/^\s+//' -e 's/\s+$$//'

其中一个使用管道

-e 's/\S*\.\S*|^\s+|\s+$$//g'

?

较短的 sed 命令不 trim 字符串(两个表达式的目的)。

为什么不起作用?如何解决这个问题(当然不用诉诸多种表达方式)?

OS 是 Ubuntu 14.10。我对使用替代工具不感兴趣,但对 如何 在正则表达式中使用管道和从 makefile 调用的 sed 感兴趣。

Arkanosis 是正确的:组合是错误的,shell 也是错误的。它与 make 没有任何关系:

echo "    thing.js myapp.mod1.js otherthing.js myapp.mod1.submod.js myapp.othermodule.js   " \
    | sed -r -e 's/\s\S*myapp\.(\w+)\.js\b/ /g' \
             -e 's/\S*\.\S*//g' -e 's/^\s+//' -e 's/\s+$//' -e 's/\b\s+\b/,/g' \
          > /tmp/x.out \
    && echo "|$(cat /tmp/x.out)|"

显示:

|mod1,othermodule|

现在使用一体化方法:

echo "    thing.js myapp.mod1.js otherthing.js myapp.mod1.submod.js myapp.othermodule.js   " \
    | sed -r -e 's/\s\S*myapp\.(\w+)\.js\b/ /g' \
             -e 's/\S*\.\S*|^\s+|\s+$//g' -e 's/\b\s+\b/,/g' \
          > /tmp/x.out \
    && echo "|$(cat /tmp/x.out)|"

你得到:

| mod1,othermodule|

您一定是在 shell 命令中做了一些让您认为它有效的事情。

之所以不行,是因为在原来的版本中,-e中的每一个表达式都是一个接一个地应用到字符串上的,所以都生效了。

在新版本中,所有三个条件都浓缩为一个表达式,只应用一次,并且只会选择三个备选方案中的一个(这就是管道符号表示在正则表达式中)。

正如@Arkanosis 所证明的那样,问题不在于使用 make。

正如@MadScientist 所暗示的,正则表达式有问题。

问题是,虽然字符串 通过 s/\S*\.\S*|^\s+|\s+$$//g 修剪的,但 space 最初不在字符串的末尾(即 spaces between words) 不会被表达式删除并且 end 位于字符串的末尾。

一旦清楚,解决方案就很明显了:在第三种情况下删除那些space:s/\s*\S*\.\S*\s*|^\s+|\s+$$//g

除此之外不会让任何 space 留给下一次替换,所以我最好的简单解决方案是

-e 's/\S*\.\S*//g' -e 's/^\s+|\s+$$//g'