打印第一列不在列表中的行

时间:2019-10-13 19:47:41

标签: bash

我在文件中有一个数字列表

cat to_delete.txt
2
3
6
9
11

和一个文件夹中的许多txt文件。每个文件都有制表符分隔的行(可以是多行)。

3 0.55667 0.66778 0.54321 0.12345
6 0.99999 0.44444 0.55555 0.66666
7 0.33333 0.34567 0.56789 0.34543

我想删除第一个数字(awk为$ 1)在to_delete.txt中的行,并仅打印第一个数字不在to_delete.txt中的行。所做的更改应替换旧文件。

预期产量

7 0.33333 0.34567 0.56789 0.34543

这是我到目前为止所获得的,不会删除任何内容;

for file in *.txt; do awk '$1 != /2|3|6|9|11/' "$file" > "$tmp" && mv "$tmp" "$file"; done

我在这里浏览了许多类似的问题,但仍然无法使它起作用。我还尝试了grep -v -f to_delete.txt和sed -n -i'/ $ to_delete /!p'

感谢您的帮助。谢谢!

2 个答案:

答案 0 :(得分:2)

awk:

$ awk 'NR==FNR{a[$1];next}!($1 in a)' delete file

输出:

7 0.33333 0.34567 0.56789 0.34543

解释:

$ awk '
NR==FNR {       # hash records in delete file to a hash
    a[$1]       
    next
}
!($1 in a)      # if $1 not found in record in files after the first, output
' delete files*   # mind the file order

答案 1 :(得分:0)

我的第一个想法是:

printf "%s\n" *.txt | xargs -n1 sed -i "$(sed 's!.*!/& /d!' to_delete.txt)"
  1. printf "%s\n" *.txt-在单独的行中分别输出* .txt文件
  2. | xargs -n1对将行内容作为输入的每一行执行以下命令
  3. sed -i-就地编辑文件
  4. $( ... )-命令替换
  5. sed 's!.*!/^& /d!' to_delete.txt-对于to_delete.txt中的每一行,在该行后附加/^,并在后缀后附加/d。这样,从数字列表中我可以获得要删除的正则表达式列表,例如:

/^2 /d
/^3 /d
/^6 /d

,依此类推。告诉sed删除与正则表达式匹配的行-以数字开头的行,后跟一个空格。

但是我认为awk会更简单。您可以这样做:

awk '$1 != 2 && $1 != 3 && $1 != 6 ... and so on ...`

但这将是冗长的,难以理解的。从文件中读取地图,然后检查数字是否在数组中会更容易:

awk 'FNR==NR{ map[$1] } FNR!=NR && !($1 in map)' to_delete.txt "$file"

FNR==NR仅对于第一个文件为true。因此,当我们阅读它时,我们设置了map[$1](我们“设置”了它,以至于存在这样的元素)。然后FNR!=NR对于第二个文件为true,我们检查该文件的第一个元素是否为映射中的键。如果不是,则表达式为真,并且将打印出该行。

一起:

for file in *.txt; do awk 'FNR==NR{ map[$1] } FNR!=NR && !($1 in map)' to_delete.txt "$file" > "$tmp"; mv "$tmp" "$file"; done