我想在 bash 中删除文件的特定行。
我目前正在做的是获取行号并传递它以便sed
删除这一行:
awk '/qr/{ print NR; exit }' test | sed -i "${1}d" test
该awk
部件运行良好,但在这种状态下,该sed
部件会删除文件(名为 test)的所有内容。
但是,当我在没有变量的情况下执行此操作时:
sed -i '1d' test
效果很好。
我究竟做错了什么 ?
答案1
${1}
被当前上下文中的第一个参数替换;它不会从awk
您的示例中的输出中读取任何内容。
如果您想保留awk
和sed
,一种方法是将 的输出存储awk
在变量中:
line=$(awk '/qr/{ print NR; exit }' test); sed -i "${line}d" test
但如果文件没有任何包含“qr”的行,则效果不佳。
更好的方法可能是仅使用sed
:
sed -i "/qr/d" test
但这将删除所有匹配的行,而不仅仅是第一行。
AWK(或者更确切地说gawk
,GNU 实现,从版本 4.1.0 开始) 等价于上面的是
gawk -i inplace '!/qr/' test
或者,仅替换第一个实例,
gawk -i inplace '/qr/ && !i { i++; next; } 1' test
答案2
给定这个输入文件:
$ cat file
foo
qr
bar
如果你真的要使用这种方法,那么它会是(没有-i
这样你就可以看到 sed 的效果):
$ awk '/qr/{print NR; exit}' file | xargs -n 1 -I {} sed '{}d' file
foo
bar
但当然,这是一个毫无意义的 xargs+sed 管道,你应该做的只是:
awk '!f && /qr/{f=1; next} 1' file > tmp && mv tmp file
或者使用支持它的最新版本的 gawk:
awk -i inplace '!f && /qr/{f=1; next} 1' file
答案3
假设您只想删除第一次出现的模式,您可以awk
完全使用:
awk '/qr/{if (!i++) next}1' test
这将打印1
除第一行匹配之外的所有行 ( ) /qr/
(其中i
仍然为零,因此next
将在“打印”操作生效之前发出该命令)。
如果您需要 的“就地”编辑功能sed -i
,和你有 GNU awk
> 4.1.0,你可以使用“inplace”扩展:
awk -i inplace '/qr/{if (!i++) next}1' test
答案4
如果您只想删除第一个匹配行,那么
sed "0,/qr/{/qr/d;}" file
-i
测试后只需将 nline 放入
这只处理从第一行到第一个匹配的地址qr
0,/qr/
并删除该地址范围中包含的任何行qr
{/qr/d;}