从单个源到多个目标的并行文件复制?


15

我想将光学介质上的几个大文件复制到多个目标上,在这种情况下,我将两个硬盘驱动器连接到同一台计算机上。是否有一个可以像以下功能的实用程序:

copy source target1 target2 ... targetN

Answers:


23

对于单个文件,您可以tee用来复制到多个位置:

cat <inputfile> | tee <outfile1> <outfile2> > <outfile3>

或者,如果您更喜欢已简化的版本:

tee <outfile1> <outfile2> > <outfile3> < <inputfile>

请注意,正如丹尼斯在注释tee输出中指出的那样,stdout以及列出的文件,因此在上面的示例中使用重定向指向文件3。您也可以将其重定向到/dev/null以下位置-这具有使命令行中的文件列表更一致的优点(这可能使编写可变数量文件的解决方案更加容易),但效率较低(尽管效率差小:关于与使用之间的差cat版本或版本,而不cat):

cat <inputfile> | tee <outfile1> <outfile2> <outfile3> > /dev/null

您可能find很容易将上述方法之一结合起来,以便在一个目录中处理多个文件,而对在目录结构中分散的文件进行操作则不那么容易。否则,您可能只需要将多个复制操作作为单独的任务并行关闭,并希望OS磁盘缓存足够明亮和/或足够大,以使每个并行任务都使用从第一个缓存的读取数据,而不是导致驱动器磁头ing不休。

可用性:tee通常在标准Linux设置和其他与UNIX或类似的Unix系统上可用,通常作为GNU“ coreutils”软件包的一部分。如果使用Windows(未指定您的问题),则应在各种Windows端口(例如Cygwin)中找到它。

进度信息:由于从光学介质复制大文件可能需要一些时间(或通过慢速网络,甚至从本地快速介质中复制甚至更大的文件),因此进度信息可能会很有用。在命令行上,我倾向于使用管道查看器(在大多数Linux发行版和许多Windows端口集合中可用,并且在不直接可用的地方很容易编译自己)-只需替换catpv

pv <inputfile> | tee <outfile1> <outfile2> > <outfile3>

我发现tee.exe是UnxUtils软件包的一部分。多谢小费!
Goyuix

5
请注意,这tee也会输出到stdout,因此您可能要这样做,tee outputfile1 outputfile2 < inputfile > /dev/null因为将二进制文件输出到终端可能会产生噪音,并且会干扰其设置。
暂停,直到另行通知。

对于目录和多个文件,只需使用tar而不是cat。例如tar cf - file1 file2 | tee >(tar xf - -C ouput1) | tar xf - -C output2
CR。

5

对于Windows:

n2ncopy将执行以下操作:

替代文字

对于Linux:

cp单独的命令可以从多个源复制,但不幸的是不能从多个目标复制。您将需要在某种循环中多次运行它。您可以使用像这样的循环并将所有目录名放在文件中:

OLDIFS=$IFS
IFS=$'\n'

for line in $(cat file.txt):
do
   cp file $line
done

IFS=$OLDIFS

或使用xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

这两个都允许您复制整个目录/多个文件。此StackOverflow文章中也对此进行了讨论。


N2NCopy链接似乎已损坏。
韦斯利


4

根据类似问题的答案,另一种方法是使用GNU Parallelcp一次运行多个实例:

parallel -j 0 -N 1 cp file1 ::: Destination1 Destination2 Destination3

上面的命令会将文件1并行复制到所有三个目标文件夹


2

在bash(Linux,Mac或Cygwin)中:

cat source | tee target1 target2 >targetN

(tee将其输入复制到STDOUT,因此对最后一个目标使用重定向)。

在Windows中,Cygwin通常是过大的。相反,您可以只添加UnxUtils项目中的exe文件,其中包括cat,tee和许多其他文件。


1

瑞安·汤普森(Ryan Thompson)的解决方案:

for x in dest1 dest2 dest3; do cp srcfile $x &>/dev/null &; done; wait;

很有道理:如果目标目录的写入速度大致相同,则srcfile将仅从磁盘读取一次。其余时间将从缓存中读取。

我会更概括一些,因此您还会得到子目录:

for x in dest1 dest2 dest3; do cp -a srcdir $x &; done; wait;

如果dest dirs的写入速度非常不同(例如,一个在ram磁盘上,另一个在NFS上),则您可能会看到在写入时将srcdir复制到dest1时读取的部分srcdir不再在磁盘高速缓存中目标2。


1

根据这个答案:https : //superuser.com/a/1064516/702806

更好的解决方案是使用tartee。该命令更为复杂,但tar似乎非常强大,可以传输,并且只需要读取一次即可。

tar -c /source/dirA/ /source/file1 | tee >(cd /foo/destination3/; tar -x) >(cd /bar/destination2/; tar -x) >(cd /foobar/destination1/; tar -x) > /dev/null

要在脚本中使用它,您可能需要使用以下命令启动脚本 bash -x script.sh


滑稽。我认为“这确实有道理,请赞成”。已投票。然后,我检查了链接…:D
卡米尔·马乔洛夫斯基'17

如果您一次复制多个文件,这显然比David Spillett(接受)的答案要好。对于单个源文件,我能看到的唯一好处tar是它将自动复制(保留)文件属性(例如,修改日期/时间,(保护)模式以及潜在的ACL,所有者/组(如果有特权),SELinux)上下文(如果适用),扩展属性(如果适用)等)……………………PS为什么用户需要使用bash -x
斯科特,

#!/bin/sh在脚本的开头使用了该命令,但是不接受该命令的语法。您可以使用bash -x#!/bin/bash在文件的开头。我不知道为什么shbash解释之间会有区别。
雷米吉拉德

卡米尔·马西洛夫斯基(Kamil Maciorowski)-我不知道为什么您的答案没有被接受。这是完美的解决方案。我想分享。
雷米吉拉德

0

在bash中:

for x in dest1 dest2 dest3; do cp srcfile $x &>/dev/null &; done; wait;

2
我认为这样做效果不佳。在理想的并行副本中,您将阅读一次,多次书写。我认为这将以1:1读取:写入。也许如果复制开始足够快并且驱动器缓存足够大,那么您实际上并不需要寻找读头。
09年

0

如果要从PowerShell在Windows中执行此操作,则默认情况下是不可能的,因为与-Path参数不同,-Destination不会接受多个参数。但是,您可以使用-Passthrough和菊花链式命令。(但这没意思。)

最好的解决办法就是让你自己的,如图所示这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.