可以在同一目录中运行多个 mv 命令(竞争条件)吗?

可以在同一目录中运行多个 mv 命令(竞争条件)吗?

我正在将大量文件(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)。

相关内容