我想知道如何删除文件中第一次出现的单词。
示例:我想从第一次出现时删除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
但这可以消除这两种情况,任何想法?
答案 0 :(得分:4)
删除文件中的第一个匹配项:
$ 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
时执行替换,并且仅在第一次出现时执行替换。
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 '/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。