Comando rsync e cp para copiar arquivos “.txt” para um único diretório (somente se já existir)

3

Eu tenho uma estrutura de diretórios com vários arquivos .txt com vários diretórios. Eu quero copiar todos esses arquivos .txt em um diretório específico. Eu dei abaixo minha estrutura de diretórios:

Dir_1
    a.txt
    x.doc
    b.txt
Dir_2
    c.txt
Dir_3
    d.txt
    e.txt
    y.doc

Para copiar todos os arquivos .txt para o diretório ~/alltxt , estou usando o comando cp abaixo.

find . -name "*.txt" -exec cp {}  ~/alltxt/  \;

Funciona bem. Agora meu diretório alltxt é como abaixo.

alltxt
        a.txt
        b.txt
        c.txt
        d.txt
        e.txt

Mas vejo que quero substituir SOMENTE os arquivos .txt alterados nessa pasta. Então, vim a saber que eu poderia fazer isso usando o comando rsync como abaixo.

find .  -name '*.txt' -exec rsync -R {} ~/alltxt/ \;

Mas copia .txt arquivos pasta por pasta como abaixo:

alltxt
  Dir_1
    a.txt
    x.doc
    b.txt
  Dir_2
    c.txt
  Dir_3
    d.txt
    e.txt
    y.doc

Mas como posso alterar meu comando rsync para funcionar como meu comando cp ?

    
por Smith Dwayne 09.02.2018 / 07:09

2 respostas

2

rsync tem um sinalizador, --existing , que evitará a cópia de arquivos que ainda não existem no destino:

find . -type f -name '*.txt' -exec rsync --existing {} "$HOME/alltxt/" ';'

Também adicionei -type f para garantir que find encontre apenas arquivos regulares e removi o -R flag ( --relative ) de rsync porque não acho que é útil nesse caso (usar esse sinalizador também é a razão pela qual você obtém os subdiretórios no destino). Eu também estou usando $HOME ao invés de ~ porque eu acho que parece mais legal.

Você também pode adicionar -a ( --archive ) à invocação rsync para preservar os tempos de propriedade e modificação, etc.

Uma abordagem semelhante, mas usando cp em vez de rsync :

find . -type f -name '*.txt' \
    -exec sh -c 'for n; do d="$HOME/alltxt/${n##*/}"; [ -f "$d" ] && cp "$n" "$d"; done' sh {} +

Isso encontra todos os arquivos .txt e chama um script de shell curto:

for n; do
    d="$HOME/alltxt/${n##*/}"
    [ -f "$d" ] && cp "$n" "$d"
done

Esse loop recebe vários arquivos .txt de find . Para cada um desses nomes n , ele cria o caminho do arquivo de destino em d , verifica se o caminho se refere a um arquivo regular existente e, em caso afirmativo, copia o arquivo fornecido para lá.

Em vez do teste [ -f "$d" ] , você pode usar [ "$d" -ot "$n" ] , o que será verdadeiro se o arquivo de destino existir e for mais antigo que o arquivo encontrado. Este é um teste fora do padrão, mas é suportado pela maioria dos shells.

A substituição de variável ${n##*/} removerá os diretórios do caminho em n , de modo que ./some/path/file.txt seja transformado em apenas file.txt (o nome base). Pode ser substituído por $(basename "$n") .

    
por 09.02.2018 / 07:32
0
shopt -s globstar
cp --update --target-directory targetDirectory sourceRootDir/**/*.txt

onde:

  • shopt -s globstar define as opções de globbing estendido, que incluem o padrão **
  • --target-directory ou -t fornece um diretório de destino para o qual copiar (ele também pode ser especificado no final de todos os argumentos, mas geralmente é mais legível colocá-lo aqui em scripts).
  • --update ou -u torna cp copiar o arquivo apenas se o destino for mais antigo i ou inexistente.
por 09.02.2018 / 09:07

Tags