Comment copier un fichier en cours d'écriture sur ssh?

20

Voici la situation:

  1. Je télécharge un fichier volumineux du client A vers un serveur à l'aide de sftp.
  2. J'ai également besoin de télécharger ce fichier du serveur vers le client B via ssh.

Ce que je voudrais faire, c'est démarrer le transfert du serveur vers le client B lorsque le téléchargement est toujours en cours depuis le client A.

Quelle est la meilleure méthode / le meilleur outil pour y parvenir?

MISE À JOUR :

Jusqu'à présent, les réponses sont intéressantes - je vais certainement les lire et les tester toutes. Points bonus pour les réponses qui ne dépendent pas du contrôle de la façon dont le client A télécharge le fichier. (C'est-à-dire que la seule chose que nous savons du client A est que le fichier est écrit dans un nom de fichier connu.)

Steven D
la source
Ooo, bonne question. C'est certainement possible, mais je ne suis au courant de rien qui le met en œuvre
Michael Mrozek

Réponses:

10

Pour un seul fichier au lieu d'utiliser SFTP, vous pouvez diriger le fichier sur ssh en utilisant catou pvsur le côté d'envoi et en utilisant teesur le serveur du milieu pour envoyer les données à un fichier et envoyer une copie sur un autre lien ssh de l'autre côté de lequel écrit simplement les données dans un fichier. Le vaudou exact requis je vais laisser comme un exercice pour le lecteur, car je n'ai pas le temps de jouer en ce moment (désolé). Cette méthode ne fonctionnerait que si la deuxième destination est accessible au public via SSH, ce qui peut ne pas être le cas si vous la décrivez comme une machine cliente.

Une autre approche, qui est moins "exécutée et attendue" mais peut être autrement plus facile à utiliser rsyncentre le serveur et le client B. La première fois que vous l'exécutez, elle peut obtenir une copie partielle des données, mais vous pouvez simplement la réexécuter pour obtenir plus de données par la suite (avec une dernière exécution une fois le transfert Client1-> Serveur terminé). Cela ne fonctionnera que si le serveur place les données directement dans le bon nom de fichier pendant le transfert SFTP (parfois vous verrez les données entrer dans un fichier temporaire qui est ensuite renommé une fois le fichier entièrement transféré - cela est fait pour rendre le la mise à jour du fichier est plus atomique mais rendra l'idée rsync inutilisable). Vous pouvez également utiliser rsync pour le transfert C1-> S au lieu de scp (si vous utilisez le--inplaceoption pour éviter le problème mentionné ci-dessus) - l'utilisation de rsync vous donnerait également une protection contre la nécessité de tout renvoyer si la connexion C1-> Server rencontre des problèmes lors d'un transfert important (j'ai tendance à utiliser à la rsync --inplace -a --progress <source> <dest>place de scp / sftp lorsque rsync est disponible, par exemple pour ce comportement "reprise de transfert").

Pour résumer ce qui précède, exécutez:

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

sur client1 puis en cours d'exécution

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

sur client2 à plusieurs reprises jusqu'à la fin du premier transfert (puis en exécutant à nouveau pour vous assurer que vous avez tout). rsyncest très bon pour ne transférer que le minimum absolu dont il a besoin pour mettre à jour un emplacement au lieu de transférer le lot entier à chaque fois. Pour la paranoïa, vous voudrez peut-être ajouter l' --checksumoption aux commandes rsync (ce qui prendra beaucoup plus de temps CPU pour les fichiers volumineux mais n'entraînera pas de transfert de données beaucoup plus important sauf si cela est nécessaire) et pour la vitesse, l' --compressoption aidera si les données que vous transférez n'est pas déjà dans un format compressé.

David Spillett
la source
5

Je ne peux pas l'essayer pour le moment, donc cela pourrait bien échouer: Mon idée est la suivante: Montez le répertoire où le fichier arrive dans le client B, par exemple avec sshfs vers / mnt / server dans le système de fichiers du client b. alors

tail -c +0 -f /mnt/server/thefileinquestion > ~/finalfile
fschmitt
la source
/ usr / bin / tail: impossible d'ouvrir `+0 'pour la lecture: aucun fichier ou répertoire de ce type - coreutils 7.4
maxschlepzig
Désolé, il manquait un -c. Je l'ai corrigé dans la réponse ci-dessus.
fschmitt
ok, un problème que je vois avec cela est que la commande ne se termine pas (-f -> suivre ...). Il faut émettre un sigQUIT ou quelque chose comme ça, quand on est sûr que le dossier est complètement écrit. Btw, en fonction de votre version de queue et de fs, tail fait en interne l'interrogation du fichier (par exemple toutes les secondes).
maxschlepzig
J'avais un cas: enregistrer un fichier vidéo sur mon disque dur, mais je voulais le copier sur une mémoire flash USB externe pour pouvoir le remettre à une personne dès que l'enregistrement est arrêté. J'ai essayé plusieurs rsync --appendpuis vérifié avec md5summais les fichiers ne correspondaient jamais. tail -c +0a fait le travail pour moi. J'avais aussi l'habitude pv -pterade suivre la progression de la queue, ça me permet de voir si ça marche. Je n'ai pas encore fini de vérifier les md5 pour vérifier que cela fonctionnait, mais ça a l'air super.
unfa
@unfa Veuillez mettre à jour votre commentaire en ajoutant une réponse ci-dessous (c'est-à-dire pas un commentaire).
Xofo
1

Je pense que cela devrait fonctionner:

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

puis

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

Ajoutez la commande pv si vous voulez voir votre débit.

mis sur écoute
la source
Vouliez-vous écrire tail -c +0?
dessert
1

Vous pouvez utiliser un fifo pour cela. Pour simplifier d'abord sans ssh impliquant seulement deux xterms:

Au xterm A:

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

Au 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

Avec ssh, cela devrait être quelque chose dans ce sens - peut-être que vous devez désactiver le caractère d'échappement dans ssh (-e aucun):

client A:

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

client B:

 $ ssh server cat fif > dest.tar.gz
maxschlepzig
la source
1

J'ai une situation qui nécessite une solution comme l'a demandé l'affiche originale. J'enregistre un match de hockey sur mon ordinateur à un endroit et j'aimerais le regarder sur mon téléviseur à un autre endroit. Le lien entre les deux emplacements permet à la copie d'aller à environ 1,3 Mo / s et l'enregistrement vidéo à environ 1,5 Mo / s. Donc, je veux copier le fichier au début de l'enregistrement. De cette façon, mon jeu de 3 heures se copiera en 3,5 heures environ. Donc, je le copie au début de l'enregistrement et je peux commencer à le regarder 30 minutes après le début. Ensuite, je peux le regarder sans interruption, presque en temps réel. Autrement dit, tant que je peux le faire copier comme il écrit le nouveau fichier. Le problème avec des outils comme rsync et scp est qu'ils regardent la taille du fichier lorsque vous lancez la copie et une fois qu'il copie cette quantité de données, il se ferme; même si le fichier a augmenté de plus du double au cours de cette copie. Et, si, j'utilise juste rsync dans une boucle pour le copier une fois qu'il s'arrête, quand le prochain rsync termine il reconstruit le fichier cible et cela tue mon lecteur vidéo et je dois recommencer à le regarder et avancer rapidement où que je sois dans le programme quand il l'a soudainement tué. Je voulais une meilleure solution et je n'ai pas pu en trouver une, j'ai donc reconstitué ceci à la place:

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'

Alors qu'est-ce que cela fait?

Tout d'abord, j'utilise dd pour copier le fichier à mesure qu'il grandit. Étant donné que le fichier se développe plus rapidement que dd ne peut l'envoyer sur le réseau, dd ne rattrape jamais la fin du fichier. Ensuite, je le redirige vers le "visualiseur de tuyaux (pv)" et je lui donne une estimation de la taille du fichier en fonction de la taille de ces fichiers. Ce n'est pas nécessaire, mais j'aime voir un indicateur de progression. Ensuite, je redirige le flux vers ma connexion ssh. La connexion ssh utilise -Cpour la compression (pour réduire la bande passante du réseau et essayer de l'accélérer), -c arcfour,blowfish-cbcpour le chiffrement le moins cher (encore une fois pour accélérer un peu les choses), le-pest pour mon port de pare-feu que j'utilise à la destination, et le ssh exécute enfin la commande dd sur la cible pour recréer le fichier tel qu'il le reçoit. Je suis heureux de dire que cette solution fonctionne très bien. Je peux regarder le match de hockey pendant la création et la copie du fichier avec seulement un court délai.

Neophraz
la source
0

Je ne suis pas sûr que la méthode tail -f fonctionne (bien qu'elle le fasse probablement si le fichier est du texte). La raison en est que je ne sais pas comment tail -f et sftp transfèrent et s'appuient sur des méta-informations.

Si sftp transfère les méta-informations en premier et que tail -f s'appuie sur les méta-informations pour lui dire qu'il n'y a plus de fichier, alors tail peut endommager la fin avec des EOF ou des null.

Si vous ne vous souciez pas du chemin de téléchargement, c'est-à-dire des téléchargements de l'ordinateur 1 vers l'ordinateur 2 des téléchargements vers l'ordinateur 3, vous pouvez essayer d'utiliser bittorent au lieu de sftp. Il semble que c'est pour cela qu'il a été conçu.

HandyGandy
la source
0

Vous pouvez essayer de lire le fichier depuis le début, mais vous devez être sûr de pouvoir l'écrire à la même vitesse au moins.

Tim Connor
la source