删除与行号从文本文件的行从另一个文件(Delete line from text file with

2019-07-30 06:44发布

我有一个包含我不得不从另一个主文件中删除行号的巨型列表的文本文件。 下面是我的数据看起来像

lines.txt

1
2
4
5
22
36
400
...

documents.txt

string1
string2
string3
...

如果我有行号的短名单,我可以很容易地已经使用

sed -i '1d,4d,5d' documents.txt

但也有很多很多的行号,我要删除。 另外,我可以使用bash / perl脚本的行号存储在数组中和回声其不是阵列中的行。 但我不知道是否有一个内置的命令来做到这一点。

任何帮助将高度赞赏。

Answer 1:

AWK oneliner应该为你工作,请参见下面的测试:

kent$  head lines.txt doc.txt 
==> lines.txt <==
1
3
5
7

==> doc.txt <==
a
b
c
d
e
f
g
h

kent$  awk 'NR==FNR{l[$0];next;} !(FNR in l)' lines.txt doc.txt
b
d
f
h

作为列翁的建议,我补充一些解释:

awk                     # the awk command
 'NR==FNR{l[$0];next;}  # process the first file(lines.txt),save each line(the line# you want to delete) into an array "l"

 !(FNR in l)'           #now come to the 2nd file(doc.txt), if line number not in "l",print the line out
 lines.txt              # 1st argument, file:lines.txt
 docs.txt               # 2nd argument, file:doc.txt


Answer 2:

好了,我说没有Perl和来砸我开发试验后试后痛苦的审判。 然而,Rexx中会做到这一点很容易;

lines_to_delete = ""

do while lines( "lines.txt" )
   lines_to_delete = lines_to_delete linein( "lines.txt" )
end

n = 0
do while lines( "documents.txt" )
   line = linein( "documents.txt" )
   n = n + 1
   if ( wordpos( n, lines_to_delete ) == 0 )
      call lineout "temp_out,txt", line
end

这将使你的输出temp_out.txt,您可以重命名为documents.txt达到目标。



Answer 3:

这里有一个办法做到这一点的sed

sed ':a;${s/\n//g;s/^/sed \o47/;s/$/d\o47 documents.txt/;b};s/$/d\;/;N;ba' lines.txt | sh

它使用sed建立一个sed命令和管道它到外壳被执行。 将所得的sed命令简单地看起来像`sed的'3D;图5d; 11D' documents.txt。

到建立它的外sed命令将d; 每个数后,循环到下一行,分支回到开始( N; ba )。 当到达最后一行( $ ),所有的换行被删除, sed '被前置,最终d' documents.txt附加。 然后b分支出来的:a - ba循环到结束,因为没有指定的标签。

下面是如何使用做joincat -n (假设lines.txt排序):

join -t $'\v' -v 2 -o 2.2 lines.txt <(cat -n documents.txt | sed 's/^ *//;s/\t/\v/')

如果lines.txt未排序:

join -t $'\v' -v 2 -o 2.2 <(sort lines.txt) <(cat -n documents.txt | sed '^s/ *//;s/\t/\v/')

编辑:

修正了在join命令,其中原始版本只输出documents.txt每一行的第一个字。



Answer 4:

这可能会为你工作(GNU SED):

sed 's/.*/&d/' lines.txt | sed -i -f - documents.txt

要么:

sed ':a;$!{N;ba};s/\n/d;/g;s/^/sed -i '\''/;s/$/d'\'' documents.txt/' lines.txt | sh


Answer 5:

我问一个类似的问题的Unix SE ,得到了精彩的答案,其中包括以下awk脚本:

#!/bin/bash
#
# filterline keeps a subset of lines of a file.
#
# cf. https://unix.stackexchange.com/q/209404/376
#
set -eu -o pipefail

if [ "$#" -ne 2 ]; then
    echo "Usage: filterline FILE1 FILE2"
    echo
    echo "FILE1: one integer per line indicating line number, one-based, sorted"
    echo "FILE2: input file to filter"
    exit 1
fi

LIST="$1" LC_ALL=C awk '
  function nextline() {
    if ((getline n < list) <=0) exit
  }
  BEGIN{
    list = ENVIRON["LIST"]
    nextline()
  }
  NR == n {
    print
    nextline()
  }' < "$2"

而另一位C版,这是更高性能的一点:

  • https://github.com/miku/filterline


文章来源: Delete line from text file with line numbers from another file