我有一个 bash 脚本,我需要在其中迭代 find 命令输出的每一行,但似乎我正在迭代 find 命令中的每个单词(以空格分隔)。到目前为止我的脚本看起来像这样:
folders=`find -maxdepth 1 -type d`
for $i in $folders
do
echo $i
done
我希望它能给出如下输出:
./dir1 and foo
./dir2 and bar
./dir3 and baz
但是我得到了这样的输出:
./dir1
and
foo
./dir2
and
bar
./dir3
and
baz
我在这里做错了什么?
folders=`foo`
总是错误的,因为它假设您的目录不会包含空格、换行符(是的,它们是有效的!)、全局字符等。一种强大的方法(需要 GNU 扩展
-print0
)如下:
while IFS='' read -r -d '' filename; do
: # something with "$filename"
done < <(find . -maxdepth 1 -type d -print0)
另一种安全可靠的方法是让
find
本身直接调用您所需的命令:
find . -maxdepth 1 -type d -exec printf '%s\n' '{}' +
请参阅 UsingFind wiki 页面以获取对该主题的完整处理。
由于您没有使用
find
的任何更高级功能,因此您可以使用简单的模式来迭代子目录:
for i in ./*/; do
echo "$i"
done
你可以这样做:
find -maxdepth 1 -type d | while read -r i
do
echo "$i"
done
基于 Charles Duffy 的回答(值得称赞!),我制作了一个 bash 函数
qfind
(引用的 find),它输出 find
但引用的所有输出。我正在将其添加到我的.bashrc
qfind() {
while IFS='' read -r -d $'\0' findOutput; do
/usr/bin/echo -n "${findOutput@Q} "
done < <(/usr/bin/find "$@" -print0)
}
带引号的字符串用空格分隔。
${findOutput@Q}
扩展为 ${findOutput}
的引用值,就像 "$(quote "$findOutput")"
一样。当-n
从echo
中移除时,也会使用换行符进行分隔。
可以这样使用
eval "folders=($(qfind . -maxdepth 1 -type d))"
for i in "${folders[@]}"; do
echo "$i"
done
需要 eval
来评估任何带引号的子字符串。
使用预定义函数,循环体中不会有任何其他命令在循环期间从 stdin 读取字符。