我正在编写一个包含find命令的脚本,以搜索给定目录下的特定源文件类型。样本调用将是:
./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
的变量扩展表现得如此。
答案 0 :(得分:2)
希望这会有效,在bash上测试。
file_sets=' -name "*.java" -o -name "*.as" '
command=`echo "find $dir -type f -a \( $file_sets \)"`
eval $command
答案 1 :(得分:1)
TLDR:在调用find_cmd_file_sets
之前,请勿在{{1}}变量中使用引号并禁用路径名扩展(set -f
)。
当你有"特别"变量内容中的字符,然后你尝试扩展该变量而不用引号,而bash会用" special"带单引号的字符,例如:
find
输出结果为:
#!/usr/bin/env bash
set -x
VAR='abc "def"'
echo $VAR
正如您所看到的,bash用+ 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
答案 2 :(得分:0)
bash
数组以允许这种嵌套引用:
file_sets=( -name "*.java" -o -name "*.as" )
find dir -type f -a \( "${file_sets[@]}" \)