如何复制仍通过ssh写入的文件?


20

情况如下:

  1. 我正在使用sftp将客户端A的大文件上传到服务器。
  2. 我还需要通过ssh将文件从服务器下载到客户端B。

我想做的是,当仍然从客户端A上载时,开始从服务器到客户端B的传输。

完成此工作的最佳方法/工具是什么?

更新

到目前为止,答案很有趣-我一定会阅读并测试所有答案。不依赖于控制客户端A如何上传文件的答案的加分。(即,我们从客户端A得知的唯一信息是该文件正在写入已知的文件名。)


噢,好问题。这当然是可能的,但我不知道能实现它的任何东西
Michael Mrozek

Answers:


10

对于单个文件而不是使用SFTP,您可以使用catpv在发送端在ssh上通过管道传输文件,并tee在中间服务器上使用既将数据发送到该文件,又通过另一端的ssh链接发送副本只是将数据写入文件。确切的伏都教具,我将作为练习留给读者使用,因为我现在没有时间演奏(抱歉)。仅当第二个目标可通过SSH公开访问时才可以使用此方法,因为您将其描述为客户端计算机时可能不是这种情况。

另一种方法,“运行和等待”较少,但可能更容易rsync在服务器和客户端B之间使用。第一次运行时,它可能会得到数据的部分副本,但是您可以重新运行然后获取更多数据(在Client1-> Server传输完成后进行最后一次运行)。仅当服务器在SFTP传输期间将数据直接输入正确的文件名时,此方法才有效(有时您会看到数据进入临时文件,一旦文件完全传输,该文件便会重命名-这样做是为了文件更新更具原子性,但会使rsync想法无法使用)。您也可以将rsync用于C1-> S传输而不是scp(如果使用--inplace避免上述问题的选项)-如果C1-> Server连接在大传输期间遇到问题,使用rsync还可以为您提供保护,使其无需重新发送所有内容(rsync --inplace -a --progress <source> <dest>当rsync可用时,我倾向于使用scp / sftp代替,例如这种“转移简历”行为)。

总结以上内容,运行:

rsync --inplace -a --progress <source> user@server:/<destination_file_or_folder>

在client1上然后运行

rsync --inplace -a --progress user@server:/<destination_file_or_folder> <destination_on_cli2>

重复在client2上,直到第一次传输完成(然后再次运行以确保您拥有一切)。rsync非常擅长仅传输需要更新位置的绝对最小值,而不是每次都传输整个批次。对于妄想症,您可能希望将--checksum选项添加到rsync命令(大文件将花费更多的CPU时间,但除非需要,否则不会导致传输大量数据),并且对于速度而言,--compress如果数据有效,则该选项将有所帮助您正在传送的文件尚未采用压缩格式。


5

我目前无法尝试,所以很可能会失败:我的想法是:在客户机B的文件系统中,例如使用sshfs将文件到达的目录安装到客户机B中。然后

tail -c +0 -f /mnt/server/thefileinquestion > ~/finalfile

/ usr / bin / tail:无法打开“ +0”进行读取:没有这样的文件或目录
-coreutils

抱歉,缺少-c。我在上面的答案中修复了它。
fschmitt

好的,我看到的一个问题是命令不会终止(-f->跟进...)。当您确定文件查询已完全写入时,必须发出sigQUIT或类似的命令。顺便说一句,根据您的tail版本和fs,tail内部会对文件进行轮询(例如,每秒)。
maxschlepzig

我有一个案例:将视频文件录制到我的HDD上,但我想复制到外部USB闪存中,以便在录制停止后立即将其分发给其他人。我尝试了多个rsync --append,然后检查了md5sum但文件从未匹配。tail -c +0为我做了工作。我还用来pv -ptera监视拖尾的进度,它使我可以查看它是否在工作。我尚未完成对md5的检查以验证其是否有效,但是看起来不错。
unfa

@unfa请通过在下面添加答案(即不是评论)来更新您的评论。
Xofo

1

我认为这应该工作:

user@clientA:~$ cat file | ssh server "cat > dest"

然后

user@clientB:~$ ssh server "tail +0 -f dest" > file

如果要查看吞吐量,请添加pv命令。


你是想写东西tail -c +0吗?
甜点

1

您可以使用fifo。为了简单起见,首先不使用ssh仅涉及两个xterm:

在xterm A:

$ mkfifo fif
$ cat test.tar.gz | tee copy.tar.gz > fif

在xterm B:

$ cat fif > dest.tar.gz
$ cmp test.tar.gz dest.tar.gz
$ echo $?
0
$ cmp test.tar.gz copy.tar.gz
$ echo $?
0

使用ssh时,应该遵循这些原则-也许您必须禁用ssh中的转义字符(-e none):

客户A:

 $ ssh server mkfifo fif
 $ cat src.tar.gz | ssh "tee fif > copy.tar.gz"

客户B:

 $ ssh server cat fif > dest.tar.gz

1

我遇到的情况需要像原始海报要求的解决方案。我正在一个位置在计算机上录制曲棍球比赛,我想在另一位置在电视上观看曲棍球比赛。两个位置之间的链接使复制速度约为1.3Mb / s,而录制视频的速度约为1.5Mb / s。因此,我想在开始记录时复制该文件。这样,我的3小时游戏将在大约3.5小时内复制。因此,我在开始录制时将其复制,并且可以在开始录制30分钟后开始观看。然后,我几乎可以实时无中断地观看它。也就是说,只要我能在写入新文件时将其复制。rsync和scp之类的工具的问题在于,当您启动副本时,它们会查看文件的大小,一旦复制了那么多的数据,它就会退出。即使文件在该复制期间增长了两倍以上。而且,如果我只是在循环中使用rsync来复制它,一旦它停止,它会在下一个rsync完成时重建目标文件,这会杀死我的视频播放器,我必须重新开始观看它,然后快进到我所在的任何地方在程序中突然被杀死。我想要一个更好的解决方案,但一直找不到,所以我拼凑了一下:

dd if=2031_20160514030000.mpg |
pv --size 4653819304 |
ssh -C -c arcfour,blowfish-cbc -p 5555 myserver.com 'dd of=/media/TV/2031_20160514030000.mpg'

那么,这是做什么的呢?

首先,随着文件的增长,我使用dd复制文件。由于文件的增长速度超过了dd可以通过网络发送文件的速度,因此dd永远不会赶上文件的结尾。接下来,我将其传送到“管道查看器(pv)”,并根据这些文件通常的大小来估算文件的大小。这不是必需的,但是我喜欢看进度表。然后,将流通过管道连接到ssh连接。ssh连接-C用于压缩(减少网络带宽并尝试加快速度),-c arcfour,blowfish-cbc最便宜的加密(同样可以加快速度),-p用于我在目标处使用的防火墙端口,并且ssh最终在目标上运行dd命令以在接收到文件时重新创建该文件。我很高兴地说,这种解决方案效果很好。在创建和复制文件的过程中,我可以观看曲棍球比赛,而延迟很短。


0

我不确定tail -f方法是否有效(尽管如果文件是text,它可能会起作用)。原因是我不知道tail -f和sftp如何传输并依赖元信息。

如果sftp首先传输元信息,并且tail -f依靠元信息告诉它没有更多文件,则tail可能以EOF或null破坏结尾。

如果您不关心上传路径,即计算机1上传到计算机2上传到计算机3,则可以尝试使用bittorent而不是sftp。看来这就是它的设计目的。


0

您可以尝试从头开始读取文件,但是需要确保至少可以相同的速度写入文件。

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.