it-swarm-pt.com

Como copiar um arquivo que ainda está sendo escrito no ssh?

Aqui está a situação:

  1. Estou enviando um arquivo grande do cliente A para um servidor usando sftp.
  2. Também preciso baixar esse arquivo do servidor para o cliente B por meio de ssh.

O que eu gostaria de fazer é iniciar a transferência do servidor para o cliente B quando o upload ainda estiver acontecendo do cliente A.

Qual é o melhor método/ferramenta para fazer isso?

ATUALIZAÇÃO :

As respostas até agora são interessantes - com certeza vou ler e testar todas elas. Pontos de bônus para respostas que não dependem do controle de como o Cliente A está enviando o arquivo. (ou seja, a única coisa que sabemos do cliente A é que o arquivo está sendo gravado em um nome de arquivo conhecido.)

20
Steven D

Para um único arquivo em vez de usar SFTP, você pode canalizar o arquivo por ssh usando cat ou pv no lado de envio e usando tee no servidor do meio para enviar os dados para um arquivo lá e envie uma cópia por outro link ssh do outro lado do qual apenas grava os dados em um arquivo. O vodu exato exigido deixarei como um exercício para o leitor, pois não tenho tempo para jogar agora (desculpe). Este método só funcionaria se o segundo destino estivesse publicamente acessível via SSH, o que pode não ser o caso, pois você o descreve como uma máquina cliente.

Outra abordagem, que é menos "executar e esperar", mas de outra forma pode ser mais fácil, é usar rsync entre o servidor e o cliente B. A primeira vez que você executa isso pode obter uma cópia parcial dos dados, mas você pode simplesmente executá-lo novamente para obter mais dados depois (com uma execução final quando a transferência Client1-> Server for concluída). Isso só funcionará se o servidor colocar os dados diretamente no nome de arquivo correto durante a transferência SFTP (às vezes você verá os dados indo para um arquivo temporário que é renomeado assim que o arquivo for completamente transferido - isso é feito para tornar o a atualização do arquivo é mais atômica, mas tornará a ideia do rsync inutilizável). Você também pode usar rsync para a transferência C1-> S em vez de scp (se você usar a opção --inplace Para evitar o problema mencionado acima) - usar rsync também forneceria proteção contra a necessidade de reenviar tudo se o C1 -> A conexão do servidor apresenta problemas durante uma grande transferência (eu tendo a usar rsync --inplace -a --progress <source> <dest> Em vez de scp/sftp quando o rsync está disponível, para este comportamento de "retomada da transferência").

Para resumir o acima, executando:

rsync --inplace -a --progress <source> [email protected]:/<destination_file_or_folder>

em client1 então executando

rsync --inplace -a --progress [email protected]:/<destination_file_or_folder> <destination_on_cli2>

no client2 repetidamente até que a primeira transferência seja concluída (em seguida, executando mais uma vez para ter certeza de que tem tudo). rsync é muito bom em transferir apenas o mínimo absoluto de que precisa para atualizar um local em vez de transferir o lote inteiro a cada vez. Por paranóia, você pode querer adicionar a opção --checksum Aos comandos rsync (o que levará muito mais tempo de CPU para arquivos grandes, mas não resultará em significativamente mais dados sendo transferidos a menos que seja necessário) e para acelerar o A opção --compress Ajudará se os dados que você está transferindo ainda não estiverem em um formato compactado.

10
David Spillett

Não posso tentar no momento, então isso pode falhar: Minha ideia é esta: monte o diretório onde o arquivo está chegando no cliente B, por exemplo, com sshfs para/mnt/server no sistema de arquivos do cliente b. Então

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

Você poderia usar um fifo para isso. Para simplificar, primeiro sem ssh envolvendo apenas dois xterms:

No xterm A:

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

No 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

Com ssh, deve ser algo nesse sentido - talvez você tenha que desativar o caractere de escape em ssh (-e none):

cliente A:

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

cliente B:

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

Eu tenho uma situação que precisa de uma solução como o autor do pôster original pediu. Estou gravando um jogo de hóquei no meu computador em um local e gostaria de assistir na minha TV em outro local. O link entre os dois locais permite que a cópia chegue a cerca de 1,3 Mb/s e a gravação do vídeo seja de cerca de 1,5 Mb/s. Portanto, desejo copiar o arquivo assim que começar a gravar. Desta forma, meu jogo de 3 horas será copiado em cerca de 3,5 horas. Então, eu copio quando começa a gravar e posso começar a assisti-lo 30 minutos depois de começar. Então posso assistir sem interrupções, quase em tempo real. Isto é, contanto que eu possa copiá-lo enquanto grava o novo arquivo. O problema com ferramentas como rsync e scp é que elas olham para o tamanho do arquivo quando você inicia a cópia e, uma vez que copia essa quantidade de dados, fecha; mesmo que o arquivo tenha aumentado mais que o dobro durante a cópia. E, se eu estiver usando o rsync em um loop para copiá-lo assim que parar, quando o próximo rsync terminar, ele reconstruirá o arquivo de destino e isso mata meu reprodutor de vídeo e eu tenho que reiniciar a assisti-lo e avançar para onde eu estava no programa quando de repente o matou. Eu queria uma solução melhor e não consegui encontrar uma, então juntei as peças:

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'

Então, o que isso faz?

Primeiro, uso o dd para copiar o arquivo à medida que ele cresce. Como o arquivo cresce mais rápido do que o dd pode enviá-lo pela rede, o dd nunca alcança o final do arquivo. Em seguida, eu canalizo para "pipe viewer (pv)" e dou uma estimativa do tamanho do arquivo com base no tamanho que esses arquivos geralmente têm. Isso não é necessário, mas gosto de ver um medidor de progresso. Então, eu canalizo o fluxo para minha conexão SSH. A conexão ssh usa -C para compressão (para reduzir a largura de banda da rede e tentar aumentá-la), -c arcfour,blowfish-cbc para a criptografia menos cara (novamente para acelerar um pouco as coisas), o -p é para minha porta de firewall que estou usando no destino, e o ssh finalmente executa o comando dd no destino para recriar o arquivo conforme o recebe. Fico feliz em dizer que essa solução funciona muito bem. Posso assistir ao jogo de hóquei enquanto o arquivo está sendo criado e copiado com apenas um pequeno atraso.

1
Neophraz

Eu acho que isso deve funcionar:

[email protected]:~$ cat file | ssh server "cat > dest"

e depois

[email protected]:~$ ssh server "tail +0 -f dest" > file

Adicione o comando pv se quiser ver sua taxa de transferência.

1
wiretapped

Não tenho certeza se o método tail -f funciona (embora provavelmente funcione se o arquivo for de texto). A razão é que eu não sei como tail -f e sftp transferem e confio em meta informações.

Se o sftp transfere as metainformações primeiro e tail -f depende das metainformações para dizer que não há mais arquivo, então tail pode prejudicar o final com EOFs ou nulos.

Se você não se importar com o caminho de upload, ou seja, o computador 1 carrega para o computador 2 carrega para o computador 3, então você pode tentar top use bittorent em vez de sftp. Parece que foi projetado para isso.

0
HandyGandy

Você pode tentar ler o arquivo desde o início, mas precisa ter certeza de que pode gravá-lo com a mesma velocidade, pelo menos.

0
Tim Connor