如何在 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 命令来输出用双引号括起来的文件路径而没有换行符
使用 find [重复] 在 bash 中操作字符串(文件扩展名)