sed命令删除第一个出现的单词

时间:2015-03-30 21:03:13

标签: macos sed

我想知道如何删除文件中第一次出现的单词。

示例:我想从第一次出现时删除admin。

account    required       pam_opendirectory.so
account    sufficient     pam_self.so
account    required       pam_group.so no_warn group=admin,wheel fail_safe
account    required       pam_group.so no_warn deny group=admin,wheel ruser fail_safe

我试过了:

sudo sed -i.bak "s/admin,//1" /etc/pam.d/screensaver

但这可以消除这两种情况,任何想法?

2 个答案:

答案 0 :(得分:4)

使用sed

删除文件中的第一个匹配项:

$ sed -e ':a' -e '$!{N;ba;}' -e 's/admin,//1' file
account    required       pam_opendirectory.so
account    sufficient     pam_self.so
account    required       pam_group.so no_warn group=wheel fail_safe
account    required       pam_group.so no_warn deny group=admin,wheel ruser fail_safe

(以上是用GNU sed测试的。)

如何运作

  • -e ':a' -e '$!{N;ba;}'

    这会立即将整个文件读入模式空间。 (如果你的文件对于内存而言太大,这不是一个好方法。)

  • -e 's/admin,//1'

    这将在第一次出现admin时执行替换,并且仅在第一次出现时执行替换。

使用BSD(OSX)sed

Wintermute报告称BSD sed无法在单行中执行分支指令,并建议使用此替代方法来更改文件:

sed -i.bak -n '1h; 1!H; $ { x; s/admin,//; p; }' file

这会立即读取整个文件,然后在读完最后一行后进行替换。

更详细:

  • -n

    默认情况下,sed会打印每一行。这样就可以了。

  • 1h

    这会将第一行放在保留缓冲区中。

  • 1!H

    对于所有后续行,此追加到保留缓冲区。

  • $ { x; s/admin,//; p; }

    对于最后一行($),它会交换保持和模式缓冲区,以便模式缓冲区现在具有完整的文件。 s/admin,//执行替换,p打印结果。

使用awk

$ awk '/admin/ && !f{sub(/admin,/, ""); f=1} 1' file >file.tmp && mv file.tmp file

这导致:

account    required       pam_opendirectory.so
account    sufficient     pam_self.so
account    required       pam_group.so no_warn group=wheel fail_safe
account    required       pam_group.so no_warn deny group=admin,wheel ruser fail_safe

如何运作

  • /admin,/ && !f{sub(/admin,/, ""); f=1}

    对于每一行,检查它是否包含单词admin,以及标志f是否仍然具有其默认值零。如果是,请删除第一次出现的admin,并将标记设置为1。

  • 1

    打印每一行。 1{print $0}。[/ 1>}的隐秘简写。

答案 1 :(得分:0)

使用sed,而不读取整个文件:

sed 's/admin,//;tl;b;:l;n;bl' file

这等待成功替换,然后进入打印文件其余部分的循环。

  • s/admin,//;tl;b;:用空字符串替换admin,如果发生替换,则跳至标签l,否则打印该行并退出(下一行将以相同方式处理)。

  • :l;n;bl:定义标签l,读取行,跳至l。