测试 -d 目录 true - 子目录 false (POSIX)
Test -d directory true - subdirectory false (POSIX)
我正在尝试打印给定起始目录中的所有 directories/subdirectories。
for i in $(ls -A -R -p); do
if [ -d "$i" ]; then
printf "%s/%s \n" "$PWD" "$i"
fi
done;
此脚本 returns 在 .目录和该目录中的所有文件,但由于某种原因,子目录的测试失败。所有目录都以 $i 结尾,输出看起来完全一样。
假设我有以下结构:
foo/bar/test
echo $i 打印
foo/
bar/
test/
虽然文件夹的内容是这样列出的:
./foo:
file1
file2
./bar:
file1
file2
但是测试语句只打印:
PWD/TO/THIS/DIRECTORY/foo
出于某种原因,它 returns 对于第一级目录是正确的,但对于所有子目录都是错误的。
(ls 可能不是执行此操作的好方法,我很高兴找到解决我所有问题的 find 语句,但首先我想知道为什么这个脚本不能像你那样工作想想。)
正如评论中指出的那样,问题在于目录名称包含 :
,因此 -d
是错误的。
我想这个命令会给你想要的输出(虽然它需要 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
考虑你的输出:
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=; 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 的 "Complex Actions" 和 "Actions In Bulk" 部分。
我正在尝试打印给定起始目录中的所有 directories/subdirectories。
for i in $(ls -A -R -p); do
if [ -d "$i" ]; then
printf "%s/%s \n" "$PWD" "$i"
fi
done;
此脚本 returns 在 .目录和该目录中的所有文件,但由于某种原因,子目录的测试失败。所有目录都以 $i 结尾,输出看起来完全一样。
假设我有以下结构:
foo/bar/test
echo $i 打印
foo/
bar/
test/
虽然文件夹的内容是这样列出的:
./foo:
file1
file2
./bar:
file1
file2
但是测试语句只打印:
PWD/TO/THIS/DIRECTORY/foo
出于某种原因,它 returns 对于第一级目录是正确的,但对于所有子目录都是错误的。
(ls 可能不是执行此操作的好方法,我很高兴找到解决我所有问题的 find 语句,但首先我想知道为什么这个脚本不能像你那样工作想想。)
正如评论中指出的那样,问题在于目录名称包含 :
,因此 -d
是错误的。
我想这个命令会给你想要的输出(虽然它需要 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
考虑你的输出:
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=; 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 的 "Complex Actions" 和 "Actions In Bulk" 部分。