bash - 递归脚本无法查看子目录中的文件

时间:2013-05-25 12:44:35

标签: bash recursion

我有一个递归脚本,它迭代一个名单列表,其中一些是文件,一些是目录。

如果它是(非空)目录,我应该再次使用目录中的所有文件调用脚本,并检查它们是否合法。

进行递归调用的代码部分:

if [[ -d $var ]] ; then
    if [ "$(ls -A $var)" ]; then 
        ./validate `ls $var`
    fi
fi

检查文件是否合法的代码部分:

if [[ -f $var ]]; then
    some code
fi

但是,在进行递归调用之后,我再也无法检查该目录中的任何文件,因为它们与主脚本不在同一目录中,-f $var如果看不到它们。

有任何建议我怎样才能看到它们并使用它们?

4 个答案:

答案 0 :(得分:2)

为什么不使用find?解决问题的简单方便。

答案 1 :(得分:2)

始终引用变量,您永远不知道何时会找到带空格的文件或目录名

shopt -s nullglob
if [[ -d "$path" ]] ; then
    contents=( "$path"/* )
    if (( ${#contents[@]} > 0 )); then 
        "$0" "${contents[@]}"
    fi
fi
  • 你正在重新发明find
  • 当然,var是一个糟糕的变量名称
  • 如果您以递归方式调用脚本,则无需对脚本名称进行硬编码。
    • 您应该考虑将逻辑放入脚本中的函数中,并且函数可以递归调用自身,而不必每次都生成一个新进程来调用shell脚本。如果您这样做,请使用$FUNCNAME代替"$0"

答案 2 :(得分:2)

有些人提到了find如何解决这个问题,我只是想说明如何做到这一点:

find /yourdirectory -type f -exec ./validate {} +; 

这将在yourdirectory中找到所有常规文件,并在其所有子目录中递归,并将其路径作为参数返回到./validate{}已扩展为findyourdirectory内找到的文件的路径。最后的+表示每次验证调用都将在大量文件上,而不是在每个文件上单独调用(其中+替换为\) ,这有时会提供巨大的加速。

答案 3 :(得分:0)

一个选项是将目录(小心)更改为子目录:

if [[ -d "$var" ]] ; then
    if [ "$(ls -A $var)" ]; then 
        (cd "$var"; exec ./validate $(ls))
    fi
fi

外括号启动一个新shell,因此cd命令不会影响主shell。 execvalidate脚本的(新副本)替换原始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