0

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

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

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

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

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

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

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

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

4

4 回答 4

2

为什么不使用find?简单易行地解决问题。

于 2013-05-25T12:56:41.617 回答
2

有几个人提到了如何find解决这个问题,我只是想展示一下如何解决这个问题:

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

这将在其所有子目录中递归查找所有常规文件yourdirectory,并将它们的路径作为参数返回给./validate. 被扩展为位于{}中的文件的路径。最后意味着每次对 validate 的调用都将在大量文件上进行,而不是在每个文件上单独调用它(其中替换为 a ),这有时会提供巨大的加速。findyourdirectory++\

于 2013-05-25T17:12:25.940 回答
2

总是引用变量,你永远不知道什么时候会找到带空格的文件或目录名

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

一种选择是将目录(小心地)更改为子目录:

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

外括号启动一个新的 shell,因此该cd命令不会影响主 shell。用脚本exec(新副本)替换原始外壳。validate使用$(...)而不是反引号是明智的。一般来说,当变量名引用可能包含空格的文件名时,用双引号将变量名括起来是明智的(但见下文)。将$(ls)列出目录中的文件。

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
于 2013-05-25T16:49:58.687 回答