自从我学会了一些 bash 语法后,我就对它在日常生活中的使用非常热衷。一个著名的命令是grep
。如果要 grep 某些内容但忽略几个文件,下面的命令可能会起作用。
grep_ignore=("token_a", "token_b")
grep -rnw . -e "token2" | grep -v <(printf '%s\n' "${grep_ignore[@]}")
如何重现:
创建一些虚拟文件夹:命令运行
mkdir dummy & cd dummy
创建文件:
a.
file_token_a.txt
:命令运行echo "token1 token2" > file_token_a.txt
;b.
file_token_b.txt
:命令运行echo "token1 token3" > file_token_b.txt
c.
file_token_c.txt
:命令运行echo "token2 token3" > file_token_c.txt
命令运行:
grep_ignore=("token_a", "token_b")
grep -rnw . -e "token2" | grep -v <(printf '%s\n' "${grep_ignore[@]}")
预期输出:
./file_token_c.txt:1:token2 token3
给定输出:
./file_token_c.txt:1:token2 token3
./file_token_a.txt:1:token1 token2
答案1
您的尝试存在两个问题:
你的数组构造有一个错误的逗号,这使得第一个模式
token_a,
而不是token_a
<(printf '%s\n' "${grep_ignore[@]}")
被传递给grep -v
要搜索的文件,该模式由进程替换的文件描述符字符串组成,如/dev/fd/63
1,而不是模式列表 - 要从文件(或进程替换)中读取模式,您需要将其作为选项的-f
参数
纠正这些:
grep_ignore=("token_a" "token_b")
然后
$ grep -rnw . -e "token2" | grep -vFf <(printf '%s\n' "${grep_ignore[@]}")
./file_token_c.txt:1:token2 token3
(-F
表示将数组元素视为固定字符串而不是正则表达式)。
或者,至少在 GNU grep 中,您可以使用--exclude
(和--include
) 将匹配限制到特定文件子集,以完全避免第二次 grep。因此使用上面的例子:
$ grep -rnw . -e "token2"
./file_token_a.txt:1:token1 token2
./file_token_c.txt:1:token2 token3
但给定一个文件名数组模式(注意元素之间用空格而不是逗号分隔):
grep_ignore=("*token_a*" "*token_b*")
然后
$ grep -rnw . -e "token2" "${grep_ignore[@]/#/--exclude=}"
./file_token_c.txt:1:token2 token3
其中数组参数扩展 ${grep_ignore/#/--exclude=}
展开如下:
$ printf '%s\n' "${grep_ignore[@]/#/--exclude=}"
--exclude=*token_a*
--exclude=*token_b*
或者你可以使用括号扩展而不是数组:
grep -rnw . -e "token2" --exclude={"*token_a*","*token_b*"}
尝试一下
set -x
例如:$ grep -rnw . -e "token2" | grep -v <(printf '%s\n' "${grep_ignore[@]}") + grep --color=auto -rnw . -e token2 + grep --color=auto -v /dev/fd/63 ++ printf '%s\n' ./file_token_a.txt:1:token1 token2 ./file_token_c.txt:1:token2 token3
注意 grep 命令是如何变成的
grep --color=auto -v /dev/fd/63
?您可以进一步确认它被/dev/fd/63
视为模式而不是伪文件,如下所示:printf '%s\n' /dev/fd/{61..65} | grep -v <(printf '%s\n' "${grep_ignore[@]}")
(您会看到它
/dev/fd/63
被过滤掉了)。
答案2
grep -rnw token2 *.txt | grep -E -v "(token_a|token_b)"
在我看来,这是一种比处理数组更简单的方法。
使用 -E 来搜索扩展正则表达式,因此您可以使用 OR 运算符“(token_a|token_b)”。