将 grep 命令与单词数组一起使用

将 grep 命令与单词数组一起使用

我有一个包含一些行的文本文件,并使用以下命令将文本文件保存到数组中

readarray -t array < Textfile

文本文件包含以下内容:

123
456
789

现在我想使用 grep 命令使用数组在另一个文本文件中查找结果,因此打印出出现“123”、“456”或“789”的行。为了测试数组,我尝试让 grep 在同一文本文件中查找“123”、“456”和“789”,并输出匹配的行(如果三个字符系列中至少有一个出现)。

我试过

grep "${array[*]}" Textfile

但这没有显示任何结果。我究竟做错了什么?

答案1

首先,您可以只使用文件本身。这比尝试使用 shell 数组要简单得多:

grep -f file1.txt file2.txt

这将打印与file2.txt中任何行匹配的任何行file1.txt

如果你由于某种原因使用数组,事情会变得更加复杂。您不能只是这样做,grep "${array[*]}" Textfile因为"${array[*]}"将扩展到数组中由空格分隔的元素列表:

$ array=("foo" "bar" "baz")
$ echo "${array[*]}"
foo bar baz

这意味着您的grep命令将变为:

grep 'foo bar baz' file

foo bar baz这意味着“在文件中查找file”。你想做的是 grep foo或者 bar,或者 baz。这可以使用 -E 选项grep并加入您想要搜索的模式来完成|

grep -E 'foo|bar|baz' file

为此,您需要执行一些复杂的操作,例如:

grep -E "$(printf '%s|' "${array[@]}" | sed 's/|$//')" file

也许:

grep -E "$(export IFS="|"; echo "${array[*]}")" file

总的来说,使用文件并忘记数组会更好、更快、更容易。

答案2

grep "${array[*]}" Textfile

只要您设置IFS为换行符(或以换行符开头的任何内容),并使用---e确保它仍然有效,即使第一个元素以 开头,它就可以工作-

"${array[*]}"在类似 Korn 的 shell 中,就像"$*"在 POSIX shell 中一样,扩展为与 的第一个字符连接的元素列表$IFS$IFS的默认值为<SPC><TAB><NL>( <SPC><TAB><NL><NUL>in zsh),因此默认情况下,您将获得使用 SPC 字符连接的元素。对于grep,您需要将不同的正则表达式以换行符分隔,以便grep依次循环每个正则表达式。

IFS=$'\n'
grep -e "${array[*]}" file

在 中zsh,执行grep -e "${(pj:\n:)array}" file(显式j使用换行符而不是$IFS全局修改)或(以/样式grep -e$^array file扩​​展数组,这成为 向 提供多种模式的另一种方式)会更干净。fishrcgrep -efirst -esecond filegrep

另一种选择是执行以下操作:

printf '%s\n' "${array[@]}" | grep -f - file

grep这次通过 的stdin 而不是通过参数传递以换行符分隔的模式列表。

-F无论您的模式是固定字符串(使用)、扩展正则表达式(使用-E)还是基本正则表达式(默认),这些方法都适用。

您可能需要确保模式列表不为空:

(( ${#array[@]} > 0 )) && grep ...

grep使用空模式调用会产生不同的结果,具体取决于grep实现,并且通常不是您想要的结果。

相关内容