shell 循环遍历数组并使用grep删除匹配的模式

xurqigkl  于 2023-04-07  发布在  Shell
关注(0)|答案(2)|浏览(183)

我有一个数组

array=("Tom" "Mango" "Boy")

还有一个文件

Tom
Mango
Jam
Boy
Girl
Dog
Cat

我想从数组中删除匹配的元素并将它们写入文件。
我尝试使用for循环

for t in ${array[@]}; do grep -v "$t" "file.txt" >> "file.txt.tmp";done

然而,这并不像预期的那样工作。它每次都需要一个参数,并写入排除的内容,从而产生重复:

Mango
Jam
Boy
Girl
Dog
Cat
Tom
Jam
Boy
Girl
Dog
Cat
Tom
Mango
Jam
Girl
Dog
Cat

我想生成file.txt.tmp,并一次性删除所有匹配元素,即。

Jam
Girl
Dog
Cat

有没有一种方法可以用for循环和grep来做到这一点。我知道我可以在grep中使用由|分隔的多个模式,但我不确定如何在数组元素上使用 * 和 * 循环。
不幸的是,sed对我不起作用,因为我试图删除包含部分模式的整行,即如果有一行
Tom speaks和输入模式是Tom,我想删除整行。grep -v似乎是最简单的方法。

w7t8yxp5

w7t8yxp51#

我知道我可以在grep中使用多个模式,由|但我不知道如何使用它并循环遍历数组元素。
您可以使用command substitutionIFS化数组,类似于:

#!/usr/bin/env bash

array=("Tom" "Mango" "Boy")
pattern=$(IFS='|'; printf '%s' "${array[*]}")

grep -Ev "$pattern" file.txt

输出

Jam
Girl
Dog
Cat

检查变量pattern的值,

declare -p pattern

输出

declare -- pattern="Tom|Mango|Boy"

或者只是

array=("Tom" "Mango" "Boy")

grep -Fxv "$(printf '%s\n' "${array[@]}")" file.txt
js4nwp54

js4nwp542#

你可以把它们写在一个文件里。

$: printf "%s\n" "${array[@]}" > patfile
$: grep -vf patfile fullfile
Jam
Girl
Dog
Cat

Jetchisel's解决方案可能更好,除非您的列表大到足以使您的系统或您配置的限制(例如命令行长度或参数限制)不堪重负。
现在这两种情况都不太可能发生,但也许你使用的是旧系统,或者你的系统管理员过于苛刻。如果发生这种情况,你可能不得不使用一个文件,并使用for循环而不是printf "%s\n" "${array[@]}"
大多数问题是由于多次执行grep。每次运行grep时(所有的时间和开销都将在任何更大的任务上增加),您都会提取不匹配 this 参数的每一行,这就是为什么您会得到重复值。您必须将排除合并到一个模式或一个文件中,以便您可以在一次通过中完成。

相关问题