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


10

我将输出从中分离出来,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),但要注意的是,在我的真实数据中我可以有组名称中包含方括号,我不希望名称本身被弄乱。

Answers:


14

sed,例如awkcutperl -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'

awk和perl -n / p在每个默认为一行但可以更改的记录上运行;在这种情况下-vRS=,-054可能会有所帮助。
dave_thompson_085

5

如果您有GNU sed,则可以使用

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

会在第四个括号和后续的右括号之前添加一个空格,然后替换逗号。


1
看起来很有趣。不幸的是,它还会international (uk) location在名称中插入不需要的空格,从而影响包含方括号的组名,例如我的示例。
roaima

然后使用s/\([[:digit:]]\+\)(/\1 (/4g仅在括号前有数字的情况下使用它将添加一个空格。
格伦·杰克曼

1

@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'

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.