我在文件中有一个数字列表
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'
感谢您的帮助。谢谢!
答案 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)"
printf "%s\n" *.txt
-在单独的行中分别输出* .txt文件| xargs -n1
对将行内容作为输入的每一行执行以下命令sed -i
-就地编辑文件$( ... )
-命令替换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