我有一个递归脚本,它迭代一个名单列表,其中一些是文件,一些是目录。
如果它是(非空)目录,我应该再次使用目录中的所有文件调用脚本,并检查它们是否合法。
进行递归调用的代码部分:
if [[ -d $var ]] ; then
if [ "$(ls -A $var)" ]; then
./validate `ls $var`
fi
fi
检查文件是否合法的代码部分:
if [[ -f $var ]]; then
some code
fi
但是,在进行递归调用之后,我再也无法检查该目录中的任何文件,因为它们与主脚本不在同一目录中,-f $var
如果看不到它们。
有任何建议我怎样才能看到它们并使用它们?
答案 0 :(得分:2)
为什么不使用find?解决问题的简单方便。
答案 1 :(得分:2)
始终引用变量,您永远不知道何时会找到带空格的文件或目录名
shopt -s nullglob
if [[ -d "$path" ]] ; then
contents=( "$path"/* )
if (( ${#contents[@]} > 0 )); then
"$0" "${contents[@]}"
fi
fi
find
var
是一个糟糕的变量名称$FUNCNAME
代替"$0"
答案 2 :(得分:2)
有些人提到了find
如何解决这个问题,我只是想说明如何做到这一点:
find /yourdirectory -type f -exec ./validate {} +;
这将在yourdirectory
中找到所有常规文件,并在其所有子目录中递归,并将其路径作为参数返回到./validate
。 {}
已扩展为find
在yourdirectory
内找到的文件的路径。最后的+
表示每次验证调用都将在大量文件上,而不是在每个文件上单独调用(其中+
替换为\
) ,这有时会提供巨大的加速。
答案 3 :(得分:0)
一个选项是将目录(小心)更改为子目录:
if [[ -d "$var" ]] ; then
if [ "$(ls -A $var)" ]; then
(cd "$var"; exec ./validate $(ls))
fi
fi
外括号启动一个新shell,因此cd
命令不会影响主shell。 exec
用validate
脚本的(新副本)替换原始shell。使用$(...)
代替反向标记是明智的。通常,当引用可能包含空格的文件名时,将变量名称括在双引号中是明智的(但请参见下文)。 $(ls)
将列出目录中的文件。
Heaven会帮助您使用ls
命令;你可能应该使用*
glob扩展。请注意,包含名称为-n
的单个文件的目录会在脚本中触发语法错误。
在评论中注明Jens时,必须在下降目录层次结构时调整shell脚本(validate
)的位置。最简单的机制是在PATH上安装脚本,这样您就可以编写exec validate
甚至exec $0
而不是exec ./validate
。如果不这样做,您需要调整$0
的值 - 假设您的shell将$0
作为相对路径离开,并且不会将其转换为绝对路径。因此,代码片段的修订版可能是:
# For validate on PATH or absolute name in $0
if [[ -d "$var" ]] ; then
if [ "$(ls -A $var)" ]; then
(cd "$var"; exec $0 $(ls))
fi
fi
或:
# For validate not on PATH and relative name in $0
if [[ -d "$var" ]] ; then
if [ "$(ls -A $var)" ]; then
(cd "$var"; exec ../$0 $(ls))
fi
fi