Clonar estrutura de árvore de diretórios e copiar arquivos para os diretórios correspondentes modificados após uma data específica

6

Eu tenho uma pasta com mais de 30 subdiretórios e quero obter a lista dos arquivos que foram modificados após uma data específica (digamos, 8 de setembro, que é o caso real) e ser copiada com a mesma estrutura de árvore. somente os arquivos modificados nessa pasta

Eu tenho 30 dir, porque eu tenho a lista dos arquivos que eu preciso encontrar usando a data da última modificação Encontre a saída do comando

a/a.txt
a/b/b.txt
a/www.txt
etc..

Por exemplo eu quero a pasta "a" criada e somente a.txt nela ... assim como a outra também "a / b" ser criada e b.txt dentro dela ...

    
por Danny 18.09.2014 / 11:42

4 respostas

6

Supondo que você tenha seus arquivos desejados em um arquivo de texto, você pode fazer algo como

while IFS= read -r file; do 
    echo mkdir -p ${file%/*}; 
    cp /source/"$file" /target/${file%/*}/${file##*/}; 
done < files.txt 

Isso vai ler cada linha da sua lista, extrair o diretório e o nome do arquivo, criar o diretório e copiar o arquivo. Você precisará alterar source e target para os diretórios pai reais que você está usando. Por exemplo, para copiar /foo/a/a.txt para /bar/a/a.txt , altere source para foo e target para bar .

Eu não posso dizer a partir de sua pergunta se você deseja copiar todos diretórios e, em seguida, apenas arquivos específicos ou se você quiser apenas os diretórios que conterão arquivos. A solução acima criará apenas os diretórios necessários. Se você quiser criar todos eles, use

find /source -type d -exec mkdir -p {} /target

Isso criará os diretórios. Quando eles estiverem lá, copie os arquivos:

while IFS= read -r file; do 
    cp /source/"$file" /target/"$file"
done

Atualizar

Este pequeno script moverá todos os arquivos modificados após 8 de setembro. Ele pressupõe as versões GNU de find e touch . Supondo que você esteja usando Linux, é isso que você terá.

#!/usr/bin/env bash    

## Create a file to compare against.
tmp=$(mktemp)
touch -d "September 8" "$tmp"

## Define the source and target parent directories
source=/path/to/source
target=/path/to/target

## move to the source directory
cd "$source"

## Find the files that were modified more recently than $tmp and copy them
find ./ -type f -newer "$tmp" -printf "%h %p
find ./ -type d -exec mkdir -p ../bar/{} \;
" | while IFS= read -rd '' path file; do mkdir -p "$target"/"$path" cp "$file" "$target"/"$path" done

Estritamente falando, você não precisa do arquivo tmp. No entanto, desta forma, o mesmo script funcionará amanhã. Caso contrário, se você usar -mtime de find, você precisaria calcular a data certa todos os dias.

Outra abordagem seria primeiro encontrar os diretórios, criá-los no destino e depois copiar os arquivos:

  1. Crie diretórios todos

    find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
    
  2. Encontre e copie os arquivos relevantes

    find ../bar/ -type d -exec rmdir {} \;
    
  3. Remova todos os diretórios vazios

    while IFS= read -r file; do 
        echo mkdir -p ${file%/*}; 
        cp /source/"$file" /target/${file%/*}/${file##*/}; 
    done < files.txt 
    
por 18.09.2014 / 12:44
5

pax

Pax é a melhor ferramenta para esta tarefa. É o substituto de POSIX para cpio e tar (e, ao contrário de tar , inclui um modo de passagem, não apenas a criação e extração de arquivos). Infelizmente, ele é omitido da instalação padrão em algumas distribuições do Linux, mas é apenas uma invocação de apt-get / yum / emerge /….

O Pax tem uma limitação: os diretórios modificados recentemente serão copiados mesmo que não contenham arquivos a serem copiados. Você pode remover o diretório vazio depois (a menos que existam diretórios vazios pré-existentes no destino que você deseja preservar).

cd /path/to/source
pax -rw -pp -T 201409080000 . /path/to/destination/
find /path/to/destination/ -depth -type d -exec rmdir {} +

Mencionarei outras formas que podem ser adaptadas a casos de uso semelhantes, mas não idênticos, em que pax não possui um filtro.

Zsh

Use o qualificador de glob m para corresponder arquivos pelo tempo de modificação ( por exemplo, m-10 para arquivos modificados nos últimos 10 dias, você pode usar outras unidades) e . para corresponder aos arquivos regulares. O modificador de histórico h mantém a parte do diretório do nome do arquivo.

cd /path/to/source
for x in **/*(.m-10); do
  mkdir -p -- $x:h
  cp -p -- $x /path/to/destination/$x
done

Como alternativa, você pode usar a função zmv para copiar arquivos correspondido por uma expressão curinga. Não há uma maneira interna de criar o diretório de destino, então eu forneço uma função para fazer isso.

autoload -U zmv
mkdir_cp () {
  mkdir -p -- ${(P)#}:h
  cp -- $@
}
cd /path/to/source
zmv -p mkdir_cp -Q '**/*(.m-10)' '/path/to/destination/$f'

POSIX encontra

Com find , você pode usar -mtime -10 para corresponder aos arquivos modificados nos últimos 10 dias ou -newer reference_time para corresponder aos arquivos modificados após reference_files .

touch -t 201409080000 /tmp/reference_time
cd /path/to/source
find . -type f -newer /tmp/reference_time -exec sh -c '
  mkdir -p /path/to/destination/"${0%/*}"
  cp "$0" "/path/to/destination/$0"
' {} \;
    
por 18.09.2014 / 17:39
2

Você pode usar find com rsync para fazer isso.

find ./source/ -newer /tmp/foo -print0 | rsync -av --files-from=- --from0 ./ ./destination/ 

Teste

  1. Eu criei dois diretórios chamados source e destination .
  2. Para fins de teste, criei um arquivo temporário com um timestamp como abaixo.

    touch --date "2014-09-08" /tmp/foo
    
  3. Agora, dentro do diretório source , eu criei um monte de subdiretórios que precisam ser copiados para o diretório destination (alguns subdiretórios com espaços também, para propósitos de teste). Eu também criei alguns arquivos de amostra. o O diretório destination está vazio no momento.

  4. Alterei a data de criação de um dos arquivos dentro do sub diretório.

    touch -c -t 1110111730 oldfile
    
  5. Agora, executo o comando find conforme especificado. O código% comando encontra todos os arquivos com base na condição que especificamos e o find após o pipe recebe a lista de arquivos que o nosso O comando rsync produziu.

Agora, dentro do diretório destination , o arquivo chamado find não deveria estar lá, pois tem um tempo anterior ao que desejamos.

Então, eu vou dentro do diretório oldfile para verificar e eu tenho toda a estrutura do subdiretório que desejo e todos os arquivos que correspondem à nossa condição de localização e o arquivo chamado destination não está presente.

Referências

link

    
por 18.09.2014 / 16:41
1

É exatamente assim que cpio foi projetado para ser usado.

find . -whatever -print | cpio -pvmd /path/to/copy/to/.

Feito.

    
por 18.09.2014 / 17:13