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

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

我将输出分开,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)

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

id roaima | sed -e 's/,/\n\t/g' -e '2,$s/(/ (/'

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

相反,为了获得我想要的结果,我需要运行两个单独的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)

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

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

答案1

sed,就像awkor 或cut一样,perl -ne逐行分别作用于每一行。

sed -e code1 -e code2

实际上运行为:

while(patternspace = getline()) {
  linenumber++
  code1
  code2
} continue {print patternspace}

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

if (linenumber >= 2) sub(/foo/, "bar", patternspace)

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

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

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

s/\(\n[^(]*\)(/\1 (/g

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

id | sed 's/,\([^(]*\)(/\n\t\1 (/g'

答案2

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

id username | sed 's/(/ (/4g; s/,/\n\t/g'

它在第四个及其后的左括号之前添加一个空格,然后替换逗号。

答案3

@stéphane-chazelas 说的是真的,但你总是可以先添加空格,然后分成几行,如下所示:

sed -e 's:\([,=][0-9]*\):\1 :g' -e 's:,:\n\t:g'

或者在单个 sed 脚本中(不带-e):

sed 's:\([,=][0-9]*\):\1 :g; s:,:\n\t:g'

我们通常使用“ /”作为命令搜索的分隔符,但它也接受任何字符,因此有时使用“ :”等其他字符更容易阅读,以避免像“ /\”这样的组合。

相关内容