如何在bash中使用awk正确找到行号并使用sed删除它?

如何在bash中使用awk正确找到行号并使用sed删除它?

我想在 bash 中删除文件的特​​定行。

我目前正在做的是获取行号并传递它以便sed删除这一行:

awk '/qr/{ print NR; exit }' test | sed -i "${1}d" test

awk部件运行良好,但在这种状态下,该sed部件会删除文件(名为 test)的所有内容。

但是,当我在没有变量的情况下执行此操作时:

sed -i '1d' test

效果很好。

我究竟做错了什么 ?

答案1

${1}被当前上下文中的第一个参数替换;它不会从awk您的示例中的输出中读取任何内容。

如果您想保留awksed,一种方法是将 的输出存储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;}

相关内容