x=$(find . -name "*.txt")
echo $x

如果我在Bash shell中运行上面的代码段,我得到的是一个包含几个由空白分隔的文件名的字符串,而不是一个列表。

当然,我可以进一步用空白分隔它们以得到一个列表,但我相信有更好的方法来做到这一点。

那么,循环查找命令结果的最佳方法是什么呢?


当前回答

如果使用grep而不是find呢?

ls | grep .txt$ > out.txt

现在您可以读取这个文件,文件名以列表的形式出现。

其他回答

你可以存储你的查找输出在数组中,如果你希望以后使用输出:

array=($(find . -name "*.txt"))

现在要打印new line中的每个元素,可以使用for循环迭代数组的所有元素,也可以使用printf语句。

for i in ${array[@]};do echo $i; done

or

printf '%s\n' "${array[@]}"

你还可以使用:

for file in "`find . -name "*.txt"`"; do echo "$file"; done

这将以换行符打印每个文件名

若要仅以列表形式打印查找输出,可以使用以下方法之一:

find . -name "*.txt" -print 2>/dev/null

or

find . -name "*.txt" -print | grep -v 'Permission denied'

这将删除错误消息,并仅在新行中输出文件名。

如果您希望对文件名做一些事情,将其存储在数组中是很好的,否则不需要占用该空间,您可以直接从find输出。

(更新到包括@Socowi的卓越速度提升)

使用任何支持它的$SHELL (dash/zsh/bash…):

find . -name "*.txt" -exec $SHELL -c '
    for i in "$@" ; do
        echo "$i"
    done
' {} +

完成了。


原来的答案(更短,但更慢):

find . -name "*.txt" -exec $SHELL -c '
    echo "$0"
' {} \;
find . -name "*.txt"|while read fname; do
  echo "$fname"
done

注意:此方法和bmargulies所示的(第二个)方法在文件/文件夹名称中使用空白时是安全的。

为了在文件/文件夹名称中包含换行符,你必须使用find的-exec谓词,就像这样:

find . -name '*.txt' -exec echo "{}" \;

{}是找到的项的占位符,\;用于终止-exec谓词。

为了完整起见,让我添加另一个变体-你必须喜欢*nix的多功能性:

find . -name '*.txt' -print0|xargs -0 -n 1 echo

这将使用\0字符分隔打印项,据我所知,在任何文件系统的文件或文件夹名称中都不允许使用\0字符,因此应该涵盖所有基础。Xargs一个接一个地把它们捡起来,然后……

# Doesn't handle whitespace
for x in `find . -name "*.txt" -print`; do
  process_one $x
done

or

# Handles whitespace and newlines
find . -name "*.txt" -print0 | xargs -0 -n 1 process_one

你可以把find返回的文件名放入这样一个数组:

array=()
while IFS=  read -r -d ''; do
    array+=("$REPLY")
done < <(find . -name '*.txt' -print0)

现在,您可以循环遍历数组以访问单个项,并对它们做任何您想做的事情。

注意:它是空白安全的。