测试-d目录true - 子目录false(POSIX)

时间:2018-04-25 15:04:04

标签: shell unix testing directory posix

我试图打印给定开始目录中的所有目录/子目录。

for i in $(ls -A -R -p); do 
    if [ -d "$i" ]; then
            printf "%s/%s \n" "$PWD" "$i"
    fi
done; 

此脚本返回在中找到的所有目录。目录和该目录中的所有文件,但由于某种原因,子目录的测试失败。所有目录最终都在$ i中,输出看起来完全一样 让我们说我有以下结构:

foo/bar/test

echo $ i print

foo/
bar/
test/

虽然文件夹的内容列出如下:

./foo:
file1
file2
./bar:
file1
file2

然而,测试语句只是打印出来:

PWD/TO/THIS/DIRECTORY/foo

由于某种原因,它对于第一级目录返回true,但对所有子目录返回false。

(ls可能不是一个很好的方法,我会很高兴找到一个解决我所有问题的发现声明,但首先我想知道为什么这个脚本没有像你那样工作#39 ; d想。)

2 个答案:

答案 0 :(得分:2)

正如评论中所指出的,问题是目录名称包含:,因此-d为false。

我想这个命令可以为你提供你想要的输出(虽然它需要Bash):

# enable globstar for ** 
# disabled in non-interactive shell (e.g. a script)
shopt -s globstar 

# print each path ending in a / (all directories)
# ** expands recursively
printf '%s\n' **/*/

标准方法是自己进行递归,或使用find

find . -type d

答案 1 :(得分:1)

考虑你的输出:

dir1:
dir1a

现在,以下情况属实:

[ -d dir1/dir1a ]

但这不是你的代码所做的;相反,它运行:

[ -d dir1a ]

为避免这种情况,请勿尝试解析ls;如果你想在基线POSIX sh中实现递归,那么自己动手:

callForEachEntry() {
  # because calling this without any command provided would try to execute all found files
  # as commands, checking for safe/correct invocation is essential.
  if [ "$#" -lt 2 ]; then
    echo "Usage: callForEachEntry starting-directory command-name [arg1 arg2...]" >&2
    echo "  ...calls command-name once for each file recursively found" >&2
    return 1
  fi
  # try to declare variables local, swallow/hide error messages if this fails; code is
  # defensively written to avoid breaking if recursing changes either, but may be faulty if
  # the command passed as an argument modifies "dir" or "entry" variables.
  local dir entry 2>/dev/null ||: "not strict POSIX, but available in dash"
  dir=$1; shift
  for entry in "$dir"/*; do
    # skip if the glob matched nothing
    [ -e "$entry" ] || [ -L "$entry" ] || continue
    # invoke user-provided callback for the entry we found
    "$@" "$entry"
    # recurse last for if on a baseline platform where the "local" above failed.
    if [ -d "$entry" ]; then
      callForEachEntry "$entry" "$@"
    fi
  done
}

# call printf '%s\n' for each file we recursively find; replace this with the code you
# actually want to call, wrapped in a function if appropriate.
callForEachEntry "$PWD" printf '%s\n'

find也可以安全使用,但作为原始代码ls使用方式的替代方式 - for dir in $(find . -type d)就像马车一样。相反,请参阅"复杂动作"和"散装行动" Using Find的一部分。