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

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

Quero mover arquivos maiores que "300 MB" 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, uma "mudança" 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 +300mmas e depois? e infelizmente alguns dos arquivos possuem todos os tipos de caracteres que você pode encontrar no teclado.

Eu estive olhando para issofioonde alguém está falando cpiomas não conheço esse programa...

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

Responder1

A maneira mais fácil é comzsh. Você pode usareliminatórias globaispara combinar arquivos de acordo com critérios como tipo e tamanho. Opadrão curinga **/corresponde a qualquer nível de subdiretórios. Omodificadores de histórico he tsão maneiras fáceis de extrair o diretório e a parte base de um nome de arquivo. Chame mkdir -ppara 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 forma portátil é com find. Use -execpara invocar um trecho 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 aproveitar múltiplas CPUs, mas a CPU raramente é um gargalo na E/S.

Responder2

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

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

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

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 se for necessário executar a rotina copiar e remover para colocar os arquivos em um sistema de arquivos diferente.

Responder3

Resumidamente:

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

Porém, todos os subdiretórios em dirB devem existir antes de você começar. Por esse motivo, sugiro que você execute 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

(Em relação ao cp(1) no mesmo tópico que você mencionou, não é bom para você, pois irá copiar todos os arquivos e construa o subdiretório denominado dirA em dirB. A bandeira-Tpode resolver este problema)

Responder4

Isso deveria cobrir tudo.

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, verifique a integridade e, se estiver satisfeito com os comandos propostos, execute-o novamente sem os echoelementos.

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

informação relacionada