为什么grep忽略包含要忽略的目录的shell变量?

use*_*353 0 bash shell grep

在Mac OS X上,我有一个像这样的bash脚本:

# Directories excluded from grep go here.
EXCLUDEDIR="--exclude-dir={node_modules,.git,tmp,angular*,icons,server,coffee}"

# This grep needs to include one line below the hit.
grep -iIrn -A1 $EXCLUDEDIR -e "class=[\"\']title[\"\']>$" -e "<div class=\"content" . > microcopy.txt
Run Code Online (Sandbox Code Playgroud)

但它似乎无视$EXCLUDEDIR.如果我只是--exclude-dir直接使用它,它的工作原理.为什么不扩展变量并正常工作?

tri*_*eee 5

大括号在技术上是一个错误.当它们在变量中时,它们是逐字包含的,而当您直接键入它们作为命令的一部分时,Bash会执行大括号扩展,并有效地从表达式中删除大括号.

bash$ echo --exclude-dir=moo{bar,baz}
--exclude-dir=moobar --exclude-dir=moobaz

bash$ x='moo{bar,baz}'
bash$ echo --exclude-dir=$x
--exclude-dir=moo{bar,baz}
Run Code Online (Sandbox Code Playgroud)

(不那么简单)解决方法是明确列出您的参数.通过使用数组列出要排除的目录名称可以稍微简化一下(但这不能移植到旧版本/bin/sh).

x=(node_modules .git tmp angular\* icons server coffee)
EXCLUDEDIR="${x[@]/#/--exclude-dir=}"
Run Code Online (Sandbox Code Playgroud)

反斜杠angular\*是将此通配符表达式传递给grep未展开的 - 如果shell将展开变量,则grep不会排除与子目录中的通配符表达式匹配的目录(除非它们恰好碰巧匹配当前目录中的某个扩展值).如果你nullglob有效,未转义的通配符将从列表中消失.