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

我试图使用一个数组来存储使用 find命令的文件名列表。

由于某些原因,数组无法在学校使用的 bash 中工作,但我的程序可以在我自己的笔记本电脑上工作。

所以我想知道还有没有别的办法,这就是我的办法:

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

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

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

88819 次浏览

你可以用这样的东西:

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
find . -name '*.txt' | while IFS= read -r FILE; do
echo "Copying $FILE.."
cp "$FILE" /destination
done

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

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

如果可能的话,避免反勾,因为它们已经被废弃了。它们很容易与撇号混淆,特别是在字体不好的情况下,而且它们的嵌套也不是很好。

在大多数情况下,如果您直接使用-exec、-Execdir、-ok 或-okdir 来遍历 find-result,那么您将得到最好的服务。

For 和 while 循环在处理文件名、换行符和制表符中的空格时很难做对。

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

{}不需要掩蔽。 您通常会看到一个 find/xargs 组合,它也会启动一个额外的进程:

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

我对 Johannes Weßt 的解决方案有疑问,如果我只是做一个回显,那么对于完整的文件列表来说是可行的。但是,如果我尝试在下一行运行 ffmpeg,脚本将只处理它遇到的第一个文件。由于管道的原因,我假设了一些 IFS 的有趣的事情,但是我不能理解它,所以用 for 循环代替:

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

我认为星际暂停有最干净的解决方案,但它失败时,有空白的路径。这是通过设置 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

还有一个变量可以改变 while 循环中的一些变量,这个循环使用 subshell

concat=""


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


echo "concat: '$concat'"

使用空格测试通用版本

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)