首页 > 解决方案 > 使用 SED 使用带有要删除的行号的索引来删除某些行

问题描述

我得到一个大文件,称为 file.txt,它可能有 20000 行或更多。其中一些行必须从原始文件中删除,并且必须创建一个包含剩余行的新文件,例如 newfile.txt。要删除的行在另一个文件中,例如 index.txt。所以我是这样的:

文件.txt:

line1
line2
...
line19999
line20000

索引.txt

11
56
79
...
19856

我一直在尝试使用 sed,试图让它使用索引中的数字来删除这些行,例如:

for i in ${index.txt[@]}
do
    sed -i.back '${i}d' file.txt>newfile.txt
done

但是,我收到一条错误消息 ${index.txt[@]}: bad replacement ,我不知道如何解决这个问题。

我也尝试过使用 gawk,但是代码有问题,我认为这与文件缩进制表符有关。如果有人可以提供帮助,我将不胜感激。

标签: linuxbashawksedgrep

解决方案


不要在循环调用 sed,那会很慢。

您可以将索引文件转换为 sed 脚本,然后在数据文件上调用 sed 一次:

sed -i.bak "$(sed 's/$/d/' index.txt)" file.txt

或者,正如@Hazzard17 指出的那样,忽略不只包含数字的行:

script=$(sed -n '/^[[:blank:]]*[[:digit:]]\+[[:blank:]]*$/ s/$/d/p' index.txt)
sed -i.bak "$script" file.txt

一个演示:

$ seq 20000 | sed 's/^/line/' > file.txt
$ wc file.txt
 20000  20000 188894 file.txt
$ seq 20000 | while read n; do [[ $RANDOM -le 5000 ]] && echo $n; done > index.txt
$ wc index.txt
 3083  3083 16789 index.txt
$ sed -i.bak "$(sed 's/$/d/' index.txt)" file.txt
$ wc -l file.txt{,.bak}
 16917 file.txt
 20000 file.txt.bak
 36917 total

要将文件读入数组,您可以执行以下操作:

mapfile -t indices < index.txt
for i in "${indices[@]}"; do ...; done

或者只是遍历文件

while IFS= read -r i; do ...; done < index.txt

推荐阅读