Como mover um arquivo recursivamente com base no tamanho e manter a estrutura

3

Eu quero mover arquivos maiores que "300Mb" de uma árvore de diretórios onde cada arquivo está localizado em subpastas

Exemplo: eu tenho uma estrutura de diretórios:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Aqui está o resultado esperado, um "movimento" da árvore de diretórios onde cada arquivo é movido para as subpastas:

dirB/            #  normal directory
dirB/file1       #  moved from dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  moved from dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  moved from dirA/y/file3

O find /path/ -type f -size +300m , mas e depois? e, infelizmente, alguns dos arquivos têm todos os tipos de caracteres que você pode encontrar no seu teclado.

Eu tenho olhado para isso thread onde alguém está falando sobre cpio mas eu não conheço esse programa ...

PS: o GNU Parallel está instalado se isso puder acelerar as coisas?

    
por Joakim 06.11.2016 / 19:42

4 respostas

4

A maneira mais fácil é com zsh . Você pode usar qualificadores de glob para corresponder arquivos de acordo com critérios como seu tipo e tamanho. O padrão curinga **/ corresponde a qualquer nível de subdiretórios. Os modificadores de histórico h e t são formas fáceis de extrair o diretório e a base parte de um nome de arquivo. Chame mkdir -p para criar os diretórios quando necessário.

cd dirA
for x in **/*(.Lm+300); do
  mkdir -p ../dirB/$x:h &&
    mv -- $x ../dirB/$x
done

A maneira portátil é com find . Use -exec para invocar um snippet de shell para cada arquivo.

cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
  mkdir -p "../dirB/${x%/*}"
  mv "$x" "../dirB/$x"
done' sh {} +

A paralelização raramente é útil para entrada / saída: ela permite que você aproveite várias CPUs, mas a CPU raramente é um gargalo na E / S.

    
por 07.11.2016 / 01:06
2

Perl rename é a escolha óbvia. Pode ser instalado como ren , rename ou pren :

find dirA -type f -size +300M | ren 's:^dirA/:dirB/:'

No entanto, não funciona se os arquivos forem movidos para um ponto de montagem diferente e falharão se os dirs não estiverem lá.

O GNU Parallel será mais lento:

cd dirA
find . -type f -size +300M | parallel mkdir -p ../dirB/{//}
find . -type f -size +300M | parallel mv {} ../dirB/{}

mas funcionará mesmo que seja necessário fazer a rotina de copiar e remover para colocar os arquivos em um sistema de arquivos diferente.

    
por 07.11.2016 / 10:14
0

Resumindo:

find dirA -type f -size +300m -printf "mv %p dirB/%P\n" | sh

Mas, todos os subdiretórios em dirB devem existir antes de você começar. Por esse motivo, sugiro que você faça as duas etapas a seguir:

cd dirA
find . -type f -size +300m -printf "mkdir -p ../dirB/%h\nmv %p ../dirB/%P\n" | sh

Em relação ao cpio (na verdade, resolve o problema dos subdiretórios):

(cd dirA; find . -type f -size +300m) | cpio -p -md  dirB

(Quanto ao cp (1) no mesmo tópico que você mencionou, não é bom para você, porque copiará todos os arquivos e compilam o subdiretório chamado dirA sob dirB. A bandeira -T pode resolver este problema)

    
por 07.11.2016 / 11:46
-1

Isso deve cobrir isso.

find /path -type f -size +300m | while read A ; do DEST=${A/dirA/dirB} ; echo mkdir -p $(dirname $DEST) 2>/dev/null; echo mv $A $DEST ; done

Execute-o como está, primeiro, verificação de integridade e, se estiver satisfeito com os comandos propostos, execute-o novamente sem os elementos echo .

No seu exemplo de estrutura de arquivos, geraria os seguintes comandos

mkdir -p ./dirB
mv ./dirA/file1 ./dirB/file1
mkdir -p ./dirB/x
mv ./dirA/x/file2 ./dirB/x/file2
mkdir -p ./dirB/y
mv ./dirA/y/file3 ./dirB/y/file3
    
por 06.11.2016 / 22:04