为了账号安全,请及时绑定邮箱和手机立即绑定

如何循环查找返回的文件名?

如何循环查找返回的文件名?

繁花不似锦 2019-07-19 15:16:45
如何循环查找返回的文件名?x=$(find . -name "*.txt")echo $x如果我在Bashshell中运行上面的代码,我得到的是一个包含几个文件名的字符串,该字符串由空白分隔,而不是一个列表。当然,我可以用空白将它们分开,以获得一个列表,但我确信有更好的方法。那么,循环遍历find指挥部?
查看完整描述

3 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

如果你只是为了最正确的答案而来,你可能想要我个人的偏好,find . -name '*.txt' -exec process {} \;(见这篇文章的底部)。如果你有时间的话,把剩下的部分读一遍,看看几种不同的方法,以及它们中大多数的问题。


完整的答案是:

最好的方法取决于你想做什么,但这里有几个选择。只要子树中没有文件或文件夹的名称中有空格,您就可以遍历这些文件:

for i in $x; do # Not recommended, will break on whitespace
    process "$i"done

稍微好一点,去掉临时变量x:

for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
    process "$i"done

它是你最好在可能的时候笑一笑。空白保险箱,用于当前目录中的文件:

for i in *.txt; do # Whitespace-safe but not recursive.
    process "$i"done

通过启用globstar选项,您可以在此目录和所有子目录中显示所有匹配的文件:

# Make sure globstar is enabledshopt -s globstarfor i in **/*.txt; do # Whitespace-safe and recursive
    process "$i"done

在某些情况下,例如,如果文件名已经在文件中,则可能需要使用read:

# IFS= makes sure it doesn't trim leading and trailing whitespace# -r prevents interpretation of \ escapes.while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
    process "$line"done < filename

read可安全结合使用find通过适当设置分隔符:

find . -name '*.txt' -print0 | 
    while IFS= read -r -d '' line; do 
        process $line    done

对于更复杂的搜索,您可能需要使用find,不管是用它-exec选项或有-print0 | xargs -0:

# execute `process` once for each filefind . -name \*.txt -exec process {} \;# execute `process` once with all the files as arguments*:find . -name \*.txt -exec process {} +# using xargs*find . -name \*.txt -print0 | xargs -0 process# using xargs with arguments after each filename (implies one run per filename)find . -name \*.txt -print0 | xargs -0 -I{} process {} argument

find还可以在运行命令之前将CD光盘到每个文件的目录中。-execdir而不是-exec,并且可以使用以下命令进行交互(在运行每个文件的命令之前提示符)-ok而不是-exec(或-okdir而不是-execdir).

*:技术上,两者都是findxargs(默认情况下)将在命令行中使用尽可能多的参数来运行该命令,并尽可能多地运行该命令以获得所有文件。实际上,除非您有大量的文件,否则这并不重要,而且如果您超过了长度,但是需要在同一个命令行中所有这些文件,你是索尔找个不同的方法。


查看完整回答
反对 回复 2019-07-19
?
慕侠2389804

TA贡献1719条经验 获得超6个赞

find . -name "*.txt"|while read fname; do
  echo "$fname"done

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

为了在所涵盖的文件/文件夹名称中有一些异国情调的换行符,您将不得不求助于-exec谓语find就像这样:

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

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

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

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

这将印刷品与\0据我所知,在任何文件系统中都不允许使用文件名或文件夹名中的字符,因此应该涵盖所有的基础。xargs然后一个接一个地捡起来.。


查看完整回答
反对 回复 2019-07-19
?
萧十郎

TA贡献1815条经验 获得超12个赞

不管你做什么,不要使用for环路:

# Don't do thisfor file in $(find . -name "*.txt")do
    …code using "$file"done

三个原因:

  • 如果for循环甚至要启动,则

    find

    必须完成。
  • 如果一个文件名中有任何空格(包括空格、制表符或换行符),那么它将被视为两个单独的名称。
  • 尽管现在不太可能,但您可以溢出命令行缓冲区。假设您的命令行缓冲区包含32 KB,而您的

    for

    循环返回40 kb的文本。最后的8KB将从你的

    for

    循环你永远也不会知道。

始终使用while read建造:

find . -name "*.txt" -print0 | while read -d $'\0' filedo
    …code using "$file"done

循环将在find命令正在执行。此外,即使返回带有空格的文件名,该命令也能工作。并且,您不会溢出命令行缓冲区。

这个-print0将使用NULL作为文件分隔符,而不是换行符,-d $'\0'读取时将使用NULL作为分隔符。


查看完整回答
反对 回复 2019-07-19
  • 3 回答
  • 0 关注
  • 397 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信