为find构建命令字符串

时间:2012-10-20 23:51:20

标签: bash shell

我正在尝试解析android源目录,我需要提取除某些模式之外的所有目录名称。如果您在下面注意到,现在我只在排除列表中包含了1个目录,但我将添加更多。,

find命令不会排除名为“docs”的目录。

注释掉的行有效,但另一行没有。为了便于调试,我包含了min和maxdepth,我将在以后删除它。

关于它为什么不起作用的任何评论或提示?

#! /bin/bash
ANDROID_PATH=$1
root=/
EXCLUDES=( doc )
cd ${root}
for dir in "${EXCLUDES[@]}"; do
    exclude_name_cmd_string=${exclude_name_cmd_string}$(echo \
                            "-not -name \"${dir}*\" -prune")
done
echo -e ${exclude_name_cmd_string}
custom_find_cmd=$(find ${ANDROID_PATH} -mindepth 1 -maxdepth 1 \
                    ${exclude_name_cmd_string} -type d)
#custom_find_cmd=$(find ${ANDROID_PATH} -mindepth 1 -maxdepth 1 \
#                    -not -name "doc*" -prune -type d)
echo ${custom_find_cmd} 

3 个答案:

答案 0 :(得分:4)

使用可能引用的参数构建命令字符串是个坏主意。你进入嵌套的引用级别和eval以及一堆其他危险/混乱的句法内容。

使用数组构建find;你已经将EXCLUDES合二为一了。

此外,重复的-not-prune对我来说似乎很奇怪。我会把你的命令写成这样的东西:

excludes=()

for dir in "${EXCLUDES[@]}"; do
  excludes+=(-name "${dir}*" -prune -o) 
done

find "${ANDROID_PATH}" -mindepth 1 -maxdepth 1 "${excludes[@]}" -type d -print

结果是,您希望将-name的参数作为find扩展的文字通配符传递给find,而不是shell扩展返回的文件列表,也不是包含文字引号的字符串。如果您尝试将命令构建为字符串,则很难做到这一点,但如果使用数组则很容易。

朋友不要让朋友将shell命令构建为字符串。

答案 1 :(得分:1)

当我将脚本(名为fin.sh)运行为:

bash -x fin.sh $HOME/tmp

跟踪输出的一行是:

find /Users/jleffler/tmp -mindepth 1 -maxdepth 1 -not -name '"doc*"' -prune -type d

你看到双引号周围的单引号吗?那是bash试图提供帮助。我猜你的“不工作”问题是你仍然得到输出中包含的doc*下的目录;除此之外,它似乎对我有用。

如何解决这个问题?

...似乎你找到了解决这个问题的方法......我不确定我是否会相信Bourne shell(但是Korn shell似乎同意Bash),但看起来像它可能适用于Bash。我很确定这是在过去30年左右发生的变化,但很难证明这一点;掌握旧代码并不容易。

如果您重复排除目录,我也想知道您是否需要重复-prune个选项;我对-prune并不十分熟悉。

答案 2 :(得分:0)

发现问题。它与exclude_name_cmd_string中的转义序列。 应该是正确的语法

exclude_name_cmd_string=${exclude_name_cmd_string}$(echo \
                        "-not -name ${dir}* -prune")