使用 awk 抑制行

使用 awk 抑制行

我有一个多行 Bash 变量:$WORDS每行包含一个单词。
我还有另一个多行 Bash 变量:$LIST每行也包含一个单词。

我想清除$LIST掉现在的所有词语$WORDS

我目前用while readand来做到这一点grep,但这并不性感。

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')
while read -r LINE; do
    LIST=$(echo "$LIST" | grep -v "$LINE")
done <<< "$WORDS"
echo "$LIST"

我认为我可以用它做,awk但没能成功。
有人能解释一下如何使用 awk 来做吗?

答案1

这应该可以完成您想要做的事情。

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')

echo "$LIST" | awk -v WORDS="$WORDS" '
BEGIN {
  split(WORDS,w1,"\n")
  for (w in w1) { w2[w1[w]] = 1 }
}
{
  if (w2[$0] != 1) { print $0 }
}'

它的工作原理如下。首先,我使用-vawk 命令行上的选项将单词列表作为变量传递。此变量将在 awk 程序中以名称 WORDS 可见。

BEGIN 块在处理任何输入之前执行。它包含两行

split(WORDS,w1,"\n")

此拆分命令采用 WORDS 列表并将其转换为名为 w1 的数组。

for (w in w1) { w2[w1[w]] = 1 }

此 for 循环遍历 w1 数组并生成一个名为 w2 的关联数组。将数组转换为关联数组将提高性能。

接下来我们有处理 LIST 的循环主体。

if (w2[$0] != 1) { print $0 }

这将根据我们的关联数组检查输入的每一行,并且只有在未找到单词时才打印该行。由于我们在 BEGIN 块中将每个键指定为 1,因此我们只需检查该键的值是否等于 1 即可知道它是否已定义。

答案2

我建议

echo "$LIST" | grep -vf <(echo "$WORDS")

相关内容