我有一个多行 Bash 变量:$WORDS
每行包含一个单词。
我还有另一个多行 Bash 变量:$LIST
每行也包含一个单词。
我想清除$LIST
掉现在的所有词语$WORDS
。
我目前用while read
and来做到这一点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 }
}'
它的工作原理如下。首先,我使用-v
awk 命令行上的选项将单词列表作为变量传递。此变量将在 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")