2

我正在尝试解析 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} 
4

3 回答 3

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传递给,而不是 shell 扩展返回的文件列表,也不是包含文字引号的字符串。如果您尝试将命令构建为字符串,这很难做到,但如果您使用数组,则微不足道。findfind

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

于 2012-10-21T00:38:23.710 回答
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 一致),但看起来它可能会起作用与重击。我很确定这在过去 30 年左右发生了变化,但很难证明这一点;掌握旧代码并不容易。

-prune我还想知道如果您重复排除目录是否需要重复选项;我还不够熟悉,-prune无法确定。

于 2012-10-21T00:33:31.780 回答
0

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

exclude_name_cmd_string=${exclude_name_cmd_string}$(echo \
                        "-not -name ${dir}* -prune")
于 2012-10-21T00:29:13.293 回答