括号内的Bash参数扩展不能按预期工作
我正在编写一个脚本,它包装find命令以搜索给定目录下的特定源文件类型。示例调用为:括号内的Bash参数扩展不能按预期工作
./find_them.sh --java --flex --xml dir1
上述命令将搜索dir1下的.java,.as和.xml文件。
要手动为此,我想出了以下find命令:
find dir1 -type f -a \(-name "*.java" -o -name "*.as" -o -name "*.xml" \)
由于我的脚本,我希望能够指定不同的文件,这样将搜索你最终得到的结构如下:
find_cmd_file_sets=$(decode_file_sets) # Assume this creates a string with the file sets e.g. -name "*.java" -o -name "*.as" etc
dirs=$(get_search_dirs) # assume this gives you the list of dirs to search, defaulting to the current directory
for dir in $dirs
do
find $dir -type f -a \($find_cmd_file_sets \)
done
上述脚本并不像预期的那样,你执行脚本并find命令返回没有结果之前,搅动了一段时间。 我确定我创建的decode_file_sets
和get_search_dirs
的等效项正在生成正确的结果。
一个简单的例子,如果执行直接在bash下面的shell
file_sets=' -name "*.java" -o -name "*.as" '
find dir -type f -a \($file_sets \) # Returns no result
# Executing result of below command directly in the shell returns correct result
echo find dir -type f -a \\\($file_sets \\\)
我不明白为什么在find命令的括号变量扩展将改变这一结果。如果它有什么区别,我在Windows下使用git-bash。
这真令人沮丧。任何帮助将非常感激。最重要的是,我想了解为什么$file_sets
的变量扩展是如此。
TLDR:不要叫find
前find_cmd_file_sets
变量和禁用路径扩展(set -f
)使用引号。
当你有“特殊”字符变量的内容,然后试图展开不带引号比bash的变量将围绕以“特”字用单引号,例如,每个字:
#!/usr/bin/env bash
set -x
VAR='abc "def"'
echo $VAR
的输出是:
+ VAR='abc "def"'
+ echo abc '"def"'
abc "def"
正如你可以看到,庆典包围"def"
单引号。在你的情况下,调用find
命令变为:
find ... -name '"*.java"' ...
所以它试图找到与"
启动文件,并与.java"
最终为了防止这种行为,你唯一可以做的(我知道的)是在扩展变量时使用双引号,例如:
#!/usr/bin/env bash
set -x
VAR='abc "def"'
echo "$VAR"
输出是:
+ VAR='abc "def"'
+ echo 'abc "def"'
abc "def"
唯一的问题,因为你也许已经注意到,就是现在整个变量是在引号和被视为一个参数。所以这在你的find
命令中不起作用。
剩下的唯一选择是不使用引号,既不在变量内容中,也不在扩展变量时使用引号。不过,当然,你有路径扩展的一个问题:
#!/usr/bin/env bash
set -x
VAR='abc *.java'
echo $VAR
输出是:
+ VAR='abc *.java'
+ echo abc file1.java file2.java
abc file1.java file2.java
幸运的,你可以使用set -f
禁止路径扩展:
#!/usr/bin/env bash
set -x
VAR='abc *.java'
set -f
echo $VAR
输出是:
+ VAR='abc *.java'
+ set -f
+ echo abc '*.java'
abc *.java
综上所述,下面应该工作:
#!/usr/bin/env bash
pattern='-name *.java'
dir="my_project"
set -f
find "$dir" -type f -a \($pattern \)
接受此,因为它是解决方案的最完整描述。 – ahjmorton 2014-11-10 10:12:44
希望这会工作,它在bash上进行测试。
file_sets=' -name "*.java" -o -name "*.as" '
command=`echo "find $dir -type f -a \($file_sets \)"`
eval $command
bash
阵列进行了介绍,让这种嵌套引用的:为什么你认为在一个变量的报价是一样的报价
file_sets=(-name "*.java" -o -name "*.as")
find dir -type f -a \("${file_sets[@]}" \)
在命令行? – 2014-11-05 10:26:17
我不知道你会怎样认为我相信。我使用单引号,因此变量中的双引号在作为参数使用时应该保留 – ahjmorton 2014-11-05 10:38:32
我想在for循环中有一个错误 - 它应该是***代替$ dirs中的dir *** – Jdamian 2014-11-05 10:52:01