为了将子文件夹中的所有文件移动到当前文件夹中,我使用此脚本
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 的答案非常出色。