如何在Bash脚本中处理find命令的结果?

85

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

但是,在学校使用的bash中,该数组无法工作,尽管在我的笔记本电脑上可以工作。

所以我想知道是否有另一种方法可以实现这个目的,这是我目前拥有的:

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

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

有没有不使用数组的方法?


1
如果您只对文件感兴趣,则应使用“-type f”限制查找结果。具有.txt结尾的目录是有效的,例如dir.txt。 - Uphill_ What '1
7个回答

154

您可以使用类似于以下代码:

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
D.Shawley,您能否请发一份带有for循环的示例代码?我认为它应该也适用于文件名中包含空格的情况。 - Johannes Weiss
2
使用find与'for'或'while'一起使用通常是一个不好的主意。您将文件名作为字符串传递,并获得所有空格和掩码问题,而使用未掩码的{}与finds -exec、-execdir、-ok、-okdir在一起使用没有问题。尝试a b.txt - user unknown
2
如果你想要循环具有副作用,那么使用这个结构时一定要非常小心。例如,a=1; seq 3 | while read line; do a=2; done; echo $a 输出的是 1 - rvernica
3
注意:这个 while 在管道中是第二个命令,因此在循环中所做的更改在循环结束后不会保留。我尝试将结果附加到循环外声明的变量时遇到了麻烦。引自这里:https://dev59.com/12Eh5IYBdhLWcg3wMA_M - Illya Moskvin
如果循环中的某些内容尝试从stdin读取内容,则可能会吞噬文件名的一部分。这可能会导致危险问题。 - xeruf

26

我在使用Johannes Weiß的解决方案时遇到了问题,如果我只是执行echo命令,它可以对完整的文件列表进行操作。然而,如果我试图在下一行运行ffmpeg,脚本只会处理它遇到的第一个文件。我认为这可能与管道中的IFS有关,但我无法解决它,于是我改用for循环:

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

15
文件名中包含空格会导致此操作失败。 - SpinUp __ A Davis

17

11

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

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

尽可能避免使用反引号,因为它们已经过时了。它们很容易与撇号混淆,特别是在低质量的字体中,而且嵌套也不太好。

在大多数情况下,如果您直接通过-exec、-execdir、-ok或-okdir迭代查找结果,则效果最佳。

对于文件名中含有空格、换行符和制表符的情况,使用for和while循环难以正确处理。

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

{} 不需要屏蔽。你经常会看到一个结合了find/xargs的组合,这样会启动额外的进程:

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

4
find . -name '*.txt' | while IFS= read -r FILE; do
    echo "Copying $FILE.."
    cp "$FILE" /destination
done

0

测试过带有空格的通用版本

echo $BASH_VERSION
4.2.46(2)-release

创建一些看起来很糟糕的目录和文件。
mkdir "spaces test"
cd spaces\ test/
touch 'test one'{1..5}
touch 'testone'{1..5}
mkdir test\ two
cd test\ two/
touch 'test one'{1..5}

创建并运行脚本

set -u
while read -r line
do
    echo "$line"
done < <(find "spaces test" -type f)

0

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

concat=""

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

echo "concat: '$concat'"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接