while循环-done

while循环-done

为了将子文件夹中的所有文件移动到当前文件夹中,我使用此脚本

while read f
do
    mv "$f" .
done < file_list

这很好用,但我必须file_list生成

find . -name *.avi > file_list

我想要的是将命令直接添加到我的 while 循环中

while read f
do
    mv "$f" .
done < find . -name *.avi

但 bash 告诉我 -bash: syntax error near unexpected token `.'

将 find 命令通过管道传输到 while 循环中的简单解决方案是什么?

答案1

您在这里不需要任何循环,find可以为您完成:

find . -name '*.avi' -exec mv {} . \;

答案2

您还可以使用进程替换。

while IFS= read -r f
do
    mv -- "$f" .
done < <(find . -name '*.avi' )

在 shell 中bash,与管道方式相比,它的优点是不是在子 shell 中运行循环,因此您在循环中执行的变量分配之后不会丢失。在bash(或zsh) 中,您宁愿这样做:

while IFS= read <&3 -rd '' f 
do
    mv -- "$f" .
done 3< <(find . -name '*.avi' -print0)

使用 NUL 分隔符能够处理任意文件名,使用 fd 3 而不是 0,因为可能会提示用户,并且会在 stdin 上读取答案,如果您使用 0,mv这将是输出。find

或者使用find命令本身

find . -name '*.avi' -exec mv -t . {} +

使用+意味着我们一次传递许多参数,这样mv就不必为mv每个文件运行一次调用。-t是一个 GNU 扩展。对于其他mv实现,您可以将其更改为:

find . -name '*.avi' -exec sh -c 'exec mv "$@" .' sh {} +

答案3

正确的方法是管道

find . -name '*.avi' |
while read f
do
    mv "$f" .
done 

第一个命令“”的结果find . -name *.avi将提供给第二个命令。

这称为管道(来自符号|)。您可以将管道视为临时文件,例如

find . -name '*.avi' > file1.tmp
while read f
do
    mv "$f" .
done < file1.tmp
rm file1.tmp

正如所指出的,带有空格或换行符的文件名可能会导致错误。

如果唯一的目的是移动文件,请使用@Terdon 的命令。

另外你必须引用*.avi,否则它会在第二次运行时中断。

find: paths must precede expression: `foo.avi' 
find: possible unquoted pattern after predicate `-name'?

答案4

两个现有答案之间的中间位置是“内联”查找并使用为了环形。

for f in `find . -name '*.avi' `
do
    mv "$f" .
done 

反引号使 find 命令就地执行,然后替换其输出。

缺点文件名中的空格和意外的奇怪字符可能会导致问题。 @Terdon 的答案非常出色。

相关内容