在sed的替换部分中使用时,为什么这些简单的shell命令会失败

anu*_*ava 7 macos bash shell awk sed

在试图找到这个问题的答案时,我想出了一个我无法理解的奇怪行为.

假设我有一个名为的文件 data

$> cat data
foo.png
abCd.png
bar.png
baZ.png
Run Code Online (Sandbox Code Playgroud)

任务是使用sed in line将所有带有大写ASCII字符的行替换为小写.所以输出应该是:

$> cat data
foo.png
abcd.png
bar.png
baz.png
Run Code Online (Sandbox Code Playgroud)

解决方案应该适用于非gnu sed,就像在Mac上的sed一样

我试图将这个嵌入式awk变成sed的替换部分:

sed -E 's/[^ ]*[A-Z][^ ]*.png/'$(echo \&|awk '{printf("<%s>[%s]",$0, tolower($0))}')'/' data
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这输出了:

foo.png
<abCd.png>[abCd.png]
bar.png
<baZ.png>[baZ.png]
Run Code Online (Sandbox Code Playgroud)

正如你所看到的那样,sed正在拾取带有大写字母的正确行,并且也达到awk,但是tolower()awk的功能失败并产生相同的文本作为输入.

shell专家可以解释这种奇怪的行为.

che*_*ner 10

您的awk命令在命令之前运行sed,而不是作为命令的子进程运行sed,因此awk只接收文字&符号作为其输入,因此它输出

<&>[&]
Run Code Online (Sandbox Code Playgroud)

然后将这个字符串嵌入到sed作为参数接收的字符串中,从中sed产生输出它应该是非常明显的.

事件的顺序是

  1. shell看到这个命令行

    sed -E 's/[^ ]*[A-Z][^ ]*.png/'$(echo \&|awk '{printf("<%s>[%s]",$0, tolower($0))}')'/' data
    
    Run Code Online (Sandbox Code Playgroud)
  2. 它处理命令替换(其中awk转动&<&>[&]),以产生中间命令行

    sed -E 's/[^ ]*[A-Z][^ ]*.png/'<&>[&]'/' data
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后shell sed使用该命令执行s/[^ ]*[A-Z][^ ]*.png/<&>[&]/

  • @anubhava:从sed联机帮助页:"替换中出现的&符号(\`\`&'')被替换为匹配RE的字符串.在此上下文中,"&"的特殊含义可以通过前面的方式来抑制它是反斜杠." (2认同)
  • @anubhava:这不可能; sed没有任何命令告诉它启动另一个命令.我想你可以有sed输出一系列例如awk命令,然后通过将它输出到bash来执行输出,但这将超出丑陋(并且由于shell元字符等而非常脆弱). (2认同)

Bru*_*ett 7

sed 'y/ABCDEFGHIJKLMNOPQRSYUVWXYZ/abcdefghijklmnopqrstuvwxyz/'
Run Code Online (Sandbox Code Playgroud)