我正在将大量文件(400K+)从一个目录移动到另一个目录,我有以下脚本来执行此操作(文件太多,mv 命令无法直接工作):
for file in *;
do
mv $file ..
done
如果我同时运行此脚本两次(或更多次),当 mv 命令尝试访问同一文件时是否会出现竞争条件?
我在网上查了一下,但没有找到任何明确的答案。谢谢!
答案1
确实存在一种竞争条件(但不会造成伤害)。
*
在进入循环时展开。如果您同时运行此脚本的第二个实例,那么它可能不会执行任何操作,因为它尝试移动的所有文件都已被移动。如果在移动操作期间没有在源目录中创建文件,那么错误消息应该是您最大的问题。
但总的来说,这种结构是一个非常糟糕的主意。*
展开为排序列表。 AFAIK 不可能将其停用。显然,对于 400K 文件来说,仅排序就是一场噩梦。请参阅man bash
“路径名扩展”部分:
分词后,除非设置了 -f 选项,否则 bash 会扫描每个单词中的字符 *、? 和 [。如果出现这些字符之一,则该单词被视为一种模式,并替换为与该模式匹配的按字母顺序排序的文件名列表。
此外,您不应该mv
为每个文件运行一个实例,因为您可以一次移动多个文件。
这是一个更好的解决方案(在 GNU 世界中):
find . -mindepth 1 -maxdepth 1 -exec mv --target-directory=DIRECTORY {} +
答案2
更好的解决方案是使用GNU 并行到插入多个参数。默认情况下,并行将同时运行n
作业,其n
数量是您的 CPU 的核心数量。
当像这样移动大量文件时:mv * destdir
您有时会收到错误:
bash: /bin/mv: Argument list too long
因为文件太多了。你可以这样做:
ls -1 | parallel mv {} destdir
这mv
将为每个文件运行。如果 mv 获取与该行相符的尽可能多的参数,则可以更快地完成:
ls -1 | parallel -m mv {} destdir
选项-m
是真的并行移动或复制文件很酷:
-m Multiple arguments. Insert as many arguments as the command
line length permits. If multiple jobs are being run in
parallel: distribute the arguments evenly among the jobs.
Use -j1 to avoid this.
答案3
对于那些像我一样没有parallel
可用的人:
find source_dir -type f | xargs -n 1 -P 20 -I '{}' mv '{}' dest_dir/
-P
您可以使用参数 on来定义进程数xargs
(在上例中设置为 20)。