Existe uma maneira de saber se um arquivo é feito copiando?

2

O cenário é o seguinte: A Máquina A tem arquivos que eu quero copiar para a Máquina C. A Máquina A não pode acessar diretamente o C, mas pode acessar a Máquina B que pode acessar a Máquina C. Estou usando o scp para copiar da Máquina A para B e depois de B para C.

A máquina B tem espaço de armazenamento limitado, portanto, à medida que os arquivos chegam, eu preciso copiá-los para C e excluí-los de B. A segunda cópia é muito mais rápida, portanto, isso não é problema com a largura de banda.

Eu poderia fazer isso manualmente, mas sou preguiçosa. O que eu gostaria é executar um script em B ou C que irá copiar cada arquivo para C como cada um termina . O trabalho scp está sendo executado de A.

Então, o que eu preciso é uma maneira de perguntar (de preferência de um script bash) se o arquivo X.avi é "feito" copiando. Cada um desses arquivos tem um tamanho diferente e não posso prever o tamanho ou o tempo de conclusão.

Edit: a propósito, os tempos de transferência de arquivos são de cerca de 1 hora de A para B e cerca de 10 minutos de B para C, se a escala de tempo for importante.

Mike Cooper
fonte

Respostas:

5

Uma maneira comum de fazer isso é primeiro copiá-lo para um nome de arquivo temporário, preferencialmente um arquivo oculto. Quando a cópia termina, o script que está fazendo a cópia renomeia o nome do arquivo não oculto.

O script na máquina B poderia, então, procurar por arquivos não ocultos.

O script na máquina A seria algo como isto:

for file in `ls *` ; do
    scp $file user@host:~/.${file}.tmp
    ssh user@host "mv ~/.${file}.tmp $file"
done

Embora isso não satisfaça o desejo do OP de usar a linha

scp * user@host:~/

ele realiza a mesma coisa e também permite que a máquina B transfira cada arquivo à medida que termina sem esperar pelo próximo arquivo.

bmb
fonte
O problema com isso é que na máquina A eu quero fazer scp * user@host:~/ e os arquivos que estão sendo copiados iriam mais do que encher a máquina B, então não posso mover / renomear arquivos depois que eles são copiados de A.
Mike Cooper
Ah, então, se eu entendi corretamente, você está lidando com mais de um arquivo de uma só vez? É daí que vem o problema?
Josh
Sim, esse é o problema. Eu não posso armazenar todos os arquivos em B, mas esta cópia vai demorar o suficiente para que eu não queira sentar e tomar conta assistindo a cada arquivo para terminar e depois copiá-lo. Talvez eu vá com sua versão expandida.
Mike Cooper
2

Faz lsof na máquina B mostra que scp tem o arquivo aberto? se assim for, você poderia assistir lsof e veja quando scp fecha o arquivo. Caso contrário, você poderá observar o tamanho do arquivo e depois de não ter mudado por um determinado período de tempo (5 minutos, por exemplo), copiá-lo de B para C.

Uma terceira opção seria copiar os arquivos de A para um diretório "in_progress" em C. Depois que a cópia terminar em A, execute um mv comando para sair do diretório "in_progress".

Josh
fonte
Infelizmente lsof não parece existir na máquina B. Sobre sua terceira opção, isso não funcionará, porque se eu deixar a cópia terminar antes de fazer qualquer coisa, eu vou sobrecarregar meu espaço permitido em B (algo como 10: 1). Então, qualquer solução que eu tenha que trabalhar durante a cópia.
Mike Cooper
A idéia de esperar 5 minutos é uma boa (eu pensei em algo similar), mas não tenho certeza de como isso seria feito. Alguma ideia?
Mike Cooper
Sim, eu poderia escrever um script ruby ​​rápido e sujo para você - a máquina B tem rubi?
Josh
Não. Não está sob meu controle e não parece ter nenhuma das coisas que tento usar. Eu estava esperando que o bash pudesse ter algo embutido para fazer isso. Embora eu possa ser capaz de executar o script da minha máquina local ... vou experimentar com isso.
Mike Cooper
Vou ver se consigo codificar algo assim apenas no bash. Minha destreza de rubi excede minha proeza bash no entanto. stackoverflow.com pode ser capaz de ajudar com tal script.
Josh
2

Acabei de pensar em outra opção completamente diferente. Não usa scp em tudo. Por favor, deixe-me saber se isso funcionaria:

  1. em B, crie um pipe fifo em algum lugar: mkfifo / tmp / xfer

  2. em A, não use scp, tar -cz files | ssh B 'cat > /tmp/xfer

  3. em C, corra ssh B 'cat /tmp/xfer' | tar -xz

Dessa forma, os dados não são armazenados em B, apenas passam pelo cano. A desvantagem disso é que você só pode ter uma cópia por vez ...

Você precisará garantir que o processo em C reapareça toda vez que terminar.

Josh
fonte
A maneira como você explica isso parece funcionar ... mas parece um pouco "magia negra" para o meu gosto. Eu acho que encontrei outra solução que funciona da maneira original, mas eu definitivamente vou manter esse trecho para uso posterior.
Mike Cooper
Desta forma não é realmente "magia negra", é apenas usando tubos que é uma instalação padrão do sistema operacional. Mas eu gosto da sua outra solução melhor, é menos código e provavelmente mais fácil de manter.
Josh
Ah, não, eu só quero dizer para mim, é mágico, porque eu nunca toquei com pipos de fifo e é algo que não é usado com tanta frequência quanto outras coisas. Embora algo para aprender agora. Além disso, a manutenção não é um grande problema. Isso será configurado para cerca de um dia é tudo.
Mike Cooper
2

Depois de pensar sobre as respostas postadas (em particular a idéia do @ Josh de assistir tempos modificados) eu estava tentando executar manipular os arquivos de B em C. Veja, B é anêmico quanto às ferramentas disponíveis, então nada que parecesse ser capaz de fazer o trabalho estava lá. Eu cheguei a essa solução. Esta ideia não é minha, encontrei-a nas pesquisas do Google antes desta questão. Eu descartei isso antes, já que a máquina B não tinha find utilidade.

Primeiro, monte o diretório apropriado em B em C, para que ele apareça como um sistema de arquivos local. eu usei sshfs para isso (ferramenta incrível, por sinal). Isso me permitirá usar os utilitários do C ao invés do B's.

Em segundo lugar, o comando find /the/folder/* -mmin +5 corresponderá a todos os arquivos modificados há mais de 5 minutos. Então o comando find /the/folder/* -mmin +5 -exec {} /the/other/folder \; moverá todos os arquivos que foram modificados há mais de 5 minutos para a outra pasta (que é na realidade em C, em vez de sshfs montado em B.

Finalmente, eu configurei um cron script para executar o script acima a cada 10 minutos hoje e amanhã. A linha no meu crontab fica assim.

*/5 * 22,23 9 * find /the/folder/* -mmin +5 -exec mv {} /the/other/folder \;

Espero que isso funcione. O próximo arquivo ainda não foi concluído, então não posso comentar se ele realmente funciona quando combinado com o script cron, mas fiz alguns arquivos manualmente e os semeei e eles se moveram bem. cruzar meus dedos

Edit: Isso está funcionando, embora como foi originalmente teve alguns erros, aqueles são corrigidos agora.

Mike Cooper
fonte
Isso soa como uma solução incrível
Josh
1

Não há necessidade de mkfifo. Na máquina B, execute isto:

ssh A 'tar -cz files' | ssh C 'tar -xz'

Você pode achar útil a opção -C do tar.

Se você precisar iniciar a cópia na máquina A, faça:

tar -cz files' | ssh B "ssh C 'tar -xz'"

Cuidado com a citação adequada, no entanto.

tuomassalo
fonte
0

A cópia será executada como outro processo ou você poderá forçá-la, usando uma subcamada. Então, você poderia usar ps para "assistir" o processo e ver quando ele desaparece.

Além disso, acredito que no * nix, você pode excluir o arquivo enquanto ele está sendo copiado. O sistema não irá apagá-lo até que o programa de cópia o feche. Claro, se a cópia não for bem sucedida, você perde o arquivo, portanto, não é a melhor ideia.

gbarry
fonte
Eu não preciso copiar uma vez que a cópia inteira esteja pronta, porque estou copiando muitos arquivos. Eu preciso saber quando cada arquivo individual é feito.
Mike Cooper