为什么是`sed expr1 | sed expr2` 与 `sed -e expr1 -e expr2` 不同

roa*_*ima 10 sed group

我正在拆分输出,id以提供用户所属组的更易读的逐行列表:

id roaima | sed 's/,/\n\t/g'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24(cdrom)
    25(floppy)
    ...
    822413650 (international (uk) location)
Run Code Online (Sandbox Code Playgroud)

我想将组号与其括号内的名称分开,所以我扩展了这样的表达式

id roaima | sed -e 's/,/\n\t/g' -e '2,$s/(/ (/'
Run Code Online (Sandbox Code Playgroud)

然而,这并不像我最初预期的那样。第二个表达似乎没有效果。

相反,为了获得我想要的结果,我需要运行两个单独的sed命令,如下所示:

id roaima | sed -e 's/,/\n\t/g' | sed '2,$s/(/ (/'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24 (cdrom)
    25 (floppy)
    ...
    822413650 (international (uk) location)
Run Code Online (Sandbox Code Playgroud)

为什么我需要sed在一个管道中使用两个命令而不是一个带有多个指令的命令?或者如果我可以用一个来做到这一点sed,我会怎么做?

我特别希望在每个项目的 UID/GID 值与其括号名称之间有一个空格(包括第一行的 UID 和 GID),但需要注意的是,在我的真实数据中,我可以有组在他们的名字中包含括号,我不希望名字本身被破坏。

Sté*_*las 15

sed, like awkor cutorperl -ne一个接一个地在每一行上工作。

sed -e code1 -e code2
Run Code Online (Sandbox Code Playgroud)

实际上运行为:

while(patternspace = getline()) {
  linenumber++
  code1
  code2
} continue {print patternspace}
Run Code Online (Sandbox Code Playgroud)

如果您的 code2 是2,$ s/foo/bar/,那就是:

if (linenumber >= 2) sub(/foo/, "bar", patternspace)
Run Code Online (Sandbox Code Playgroud)

由于您的输入只有一行,因此sub()永远不会运行。

在模式空间中插入换行符code1不会linenumber增加。

相反,在处理第一行也是唯一一行输入时,您有一个包含多行的模式空间。如果您想对多行模式空间的第二行及以上进行修改,您需要执行以下操作:

s/\(\n[^(]*\)(/\1 (/g
Run Code Online (Sandbox Code Playgroud)

虽然在这里当然,你也可以一次完成两个操作:

id | sed 's/,\([^(]*\)(/\n\t\1 (/g'
Run Code Online (Sandbox Code Playgroud)


gle*_*man 6

如果你有 GNU sed,你可以使用

id username | sed 's/(/ (/4g; s/,/\n\t/g'
Run Code Online (Sandbox Code Playgroud)

在第 4 个和随后的开括号之前添加一个空格,然后替换逗号。