如何在 bash 脚本中处理 find 的结果?

Posted

技术标签:

【中文标题】如何在 bash 脚本中处理 find 的结果?【英文标题】:How can I process the results of find in a bash script? 【发布时间】:2011-01-06 10:01:53 【问题描述】:

我正在尝试使用find 命令使用数组来存储文件名列表。

由于某种原因,该阵列无法在学校使用的 bash 中运行,但我的程序可以在我自己的笔记本电脑上运行。

所以我想知道是否还有其他方法可以做到这一点,这就是我所拥有的:

array = (`find . -name "*.txt"`)  #this will store all the .txt files into the array

然后我可以使用 cat 命令访问数组项并复制所有文件。

还有其他不使用数组的方法吗?

【问题讨论】:

如果您只对文件感兴趣,那么您应该使用-type f 限制查找结果。有一个以 .txt 结尾的目录是有效的,例如。目录.txt 【参考方案1】:

你可以这样使用:

find . -name '*.txt' | while read line; do
    echo "Processing file '$line'"
done

例如,制作副本:

find . -name '*.txt' | while read line; do
    echo "Copying '$line' to /tmp"
    cp -- "$line" /tmp
done

【讨论】:

在这里使用for 循环绝对是更好的选择。使用数组会起作用,只是它将整个列表读入一个变量,然后遍历该变量。此版本读取来自find 的每个文件名并内联处理它。 D.Shawley,您能否发布一个带有 for 循环的示例?我认为它也应该适用于名称中带有空格的文件。 find 与 'for' 或 'while' 一起使用通常是个坏主意。您将文件名作为字符串传递并得到所有与空格和掩码有关的问题,而将未掩码的 与 finds -exec、-execdir、-ok、-okdir 一起使用是没有问题的。试试a b.txt 如果你想循环产生副作用,我会非常小心地使用构造。例如a=1; seq 3 | while read line; do a=2; done; echo $a 打印1 小心:这个while 在子shell 中运行,因为它是管道中的第二个命令,因此在循环退出后,在该循环中所做的更改不可用。我很难将它附加到循环外声明的变量中。从这里:***.com/questions/22691436/…【参考方案2】:

我对 Johannes Weiß 的解决方案有疑问,如果我只是做一个回显,它将适用于完整的文件列表。但是,如果我尝试在下一行运行 ffmpeg,则脚本只会处理它遇到的第一个文件。由于管道,我假设了一些 IFS 有趣的事情,但我无法弄清楚并使用 for 循环运行:

for i in $(find . -name '*.mov' ); 
do
    echo "$i"
done

【讨论】:

文件名中的空格会失败【参考方案3】:

我认为 starpause 有最干净的解决方案,但是当路径中有空格时它会失败。这可以通过设置IFS 来解决。因此正确答案是:

IFS=$'\n'
for i in $(find . -name '*.mov' ); 
do
    echo "$i"
done
unset IFS

您取消设置 IFS 是为了重置 IFS 的行为以及为什么在 IFS=$'\n' 中需要 $,请参阅 https://unix.stackexchange.com/questions/184863/what-is-the-meaning-of-ifs-n-in-bash-scripting

【讨论】:

【参考方案4】:

只是不要在等号周围放置空格:

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

尽可能避免使用反引号,因为它们已被弃用。它们很容易与撇号混淆,尤其是在较差的字体中,而且它们的嵌套不太好。

在大多数情况下,如果您直接使用 -exec、-execdir、-ok 或 -okdir 遍历查找结果,您会得到最好的服务。

当涉及到文件名或换行符和制表符中的空白时,很难正确执行 For 和 while 循环。

find ./ -name "*.txt" -exec grep  ";"

不需要屏蔽。 您经常会看到一个组合 find/xargs 也会启动一个额外的过程:

find ./ -name "*.txt" | xargs grep  ";"

【讨论】:

【参考方案5】:
find . -name '*.txt' | while IFS= read -r FILE; do
    echo "Copying $FILE.."
    cp "$FILE" /destination
done

【讨论】:

【参考方案6】:

在使用子shell的while循环中更改某些变量的另一种变体

concat=""

while read someVariable
do
    echo "someVariable: '$someVariable'"
    concat="$concat someVariable")
done < <(find "/Users/alex" -name "*.txt")

echo "concat: '$concat'"

【讨论】:

以上是关于如何在 bash 脚本中处理 find 的结果?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 bash 脚本中使用 find 命令检查目录大小

Bash 脚本 - 需要 find 命令来输出用双引号括起来的文件路径而没有换行符

使用 find [重复] 在 bash 中操作字符串(文件扩展名)

Bash while 循环等待任务完成

在简单的 bash 脚本中使用 find 命令和 if 语句

检查用户是否有权执行文件