
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 +300m
mas 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 cpio
mas 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 h
e t
são maneiras fáceis de extrair o diretório e a parte base 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 forma portátil é com find
. Use -exec
para 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
, rename
ou 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 echo
elementos.
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