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

时间:2015-03-03 04:26:24

标签: 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

但似乎忽略了$EXCLUDEDIR。如果我直接使用--exclude-dir,它就可以了。为什么它不会扩展变量并正常工作?

2 个答案:

答案 0 :(得分: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}

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

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

angular\*中的反斜杠是将此通配符表达式传递给grep未展开 - 如果shell将扩展变量,grep将不会排除与子目录中的通配符表达式匹配的目录(除非它们很方便地匹配当前目录中的一个扩展值)。如果nullglob生效,则未转义的通配符将从列表中消失。

答案 1 :(得分:0)

@tripleee正确地描述了这个问题,但我认为有两种解决方法比使用数组更简单(并且,我认为,更便携):在eval命令中使用git,或者在变量赋值本身中使用echo最好使用echo方法。

使用eval

# 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.
eval grep -iIrn -A1 $EXCLUDEDIR # .... etc

这会使大括号扩展,就好像它们是字面输入一样。但请注意,如果您不小心,它可能会产生一些意想不到的副作用;例如,您可能需要添加一些额外的\来逃避引号和$ - 符号。

使用echo

这可能比eval更安全,因为您不会意外执行隐藏在EXCLUDEDIR变量中的代码。

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

# This grep needs to include one line below the hit.
grep -iIrn -A1 $EXCLUDEDIR # .... etc