单引号中grep-E表达式的bash字符串扩展

单引号中grep-E表达式的bash字符串扩展,bash,grep,Bash,Grep,在bash脚本中,我试图为grep-E构造一个字符串,使其显示为 grep -E 'alice|bar|bob|foo' 如果我在命令行测试grep--ls*|grep-E'alice | bar | bob | foo'--事情会按预期进行。它排除扩展正则表达式中与列表同名的所有文件 我发现的问题是,如果我将字符串构造为'alice | bar | bob | foo' 断开的测试用例: #!/bin/bash touch foo.txt bar.txt alice.txt bob.tx

在bash脚本中,我试图为
grep-E
构造一个字符串,使其显示为

grep -E 'alice|bar|bob|foo' 
如果我在命令行测试grep--
ls*|grep-E'alice | bar | bob | foo'
--事情会按预期进行。它排除扩展正则表达式中与列表同名的所有文件

我发现的问题是,如果我将字符串构造为
'alice | bar | bob | foo'

断开的测试用例:

#!/bin/bash touch foo.txt bar.txt alice.txt bob.txt touch alice.tmp bob.tmp foo.tmp crump.tmp dammitall.tmp EXCLUDE_PATTERN=$(echo *.txt | sed 's/\.txt /|/g' | sed 's/\.txt//') EXCLUDE_PATTERN="'""$EXCLUDE_PATTERN""'" echo "Excluding files that match the string $EXCLUDE_PATTERN" for file in *.tmp do if echo $file | grep -q -E $EXCLUDE_PATTERN then echo "Keeping $file" else echo "Deleting $file" rm -f $file fi done #!/bin/bash 触摸foo.txt bar.txt alice.txt bob.txt 触摸alice.tmp bob.tmp foo.tmp crump.tmp dammill.tmp 排除模式=$(echo*.txt | sed's/\.txt/|/g'| sed's/\.txt/')) EXCLUDE_PATTERN=“”“$EXCLUDE_PATTERN” echo“排除与字符串$EXCLUDE_模式匹配的文件” 对于*.tmp中的文件 做 如果echo$file | grep-q-E$EXCLUDE_模式 然后 echo“保留$file” 其他的 echo“删除$file” rm-f$文件 fi 完成 产出:

Excluding files that match the string 'alice|bar|bob|foo' Deleting alice.tmp Keeping bob.tmp Deleting crump.tmp Deleting dammitall.tmp Deleting foo.tmp 不包括与字符串“alice | bar | bob | foo”匹配的文件 删除alice.tmp 保留bob.tmp 删除crump.tmp 删除dammitall.tmp 删除foo.tmp 。。。但我不想删除alice.tmp或foo.tmp,因为它们在正则表达式中

我假设shell得到了一些字符,而在这个脚本中扩展字符串时没有得到这些字符,但在我的一生中,我无法弄清楚传递给
grep-E
的字符串是以何种方式被上面的“断开”脚本覆盖的

EXCLUDE_PATTERN=“$EXCLUDE_PATTERN”
这样的变体似乎没有帮助。我还没找到那根神奇的绳子

编辑以包含以下有用的注释:


使用
set-x
表示bash自己包装单引号,因此上面不正确的代码排除了在单引号周围添加单引号的

为什么要添加单引号?只需删除此行:

 EXCLUDE_PATTERN="'""$EXCLUDE_PATTERN""'"
没有这一行,我得到了以下信息:

 Excluding files that match the string alice|bar|bob|foo
 Keeping alice.tmp
 Keeping bob.tmp
 Deleting crump.tmp
 Deleting dammitall.tmp
 Keeping foo.tmp

你说得对,这很有效。我添加它们是因为命令行需要它们。为什么不同?(也非常感谢!这是我最终陷入与转义符讨价还价的泥沼中的一件事,直到忘记我尝试了什么排列…)在命令提示符下,单引号阻止管道用于重定向I/O,但不会传递到
grep
。如果引号是变量值的一部分,则在展开变量(以及正则表达式的一部分)时会传递引号。在脚本开头添加命令
set-x
。。这将指示bash向您展示它如何扩展变量和启动子流程。这是我一直用来调试这类问题的一个非常有用的技巧。不过,应该在变量引用周围使用双引号(例如,
grep-q-e“$EXCLUDE\u PATTERN”
),因为shell对替换值进行一些解析(只是不解析变量值中的引号)。在这种情况下,您可以不使用双引号,但最好养成在使用变量时使用双引号的习惯。@stevesliva:这与bash解析命令行中各种元素的顺序有关。具体地说,它在展开变量之前解析引号,因此在变量的值中加引号没有任何用处——当引号成为命令的一部分时,它们已经太晚了,无法执行您希望它们执行的操作。另一方面,在变量引用周围加上(双)引号确实很有用。shell将您的
|
字符视为管道。如果echo。。。格雷普。。“$EXCLUDE_PAT”(注意您的var名称周围的dbl引号)。而且,不要为
EX_PAT=“”“$EX_PAT”“””
操心,只要一组dbl引号就可以了。祝你好运