
Dados muitos diretórios/subdiretórios contendo muitos tipos de arquivos diferentes (csv, txt, jpg, etc.), qual comando pesquisará cada diretório recursivamente e copiará os arquivos em um novo diretório de nível superior nomeado após cada extensão.
Existe uma maneira de conseguir isso com uma linha?
Responder1
Solução
O comando a seguir listará todos os arquivos no diretório atual ( .
) e os moverá para diretórios nomeados de acordo com suas extensões ./OUTPUT
:
for file in $(find . -type f) ; do EXTENSION=$(echo "$file" |sed 's/.*\.//g') ; rsync -av $file ./OUTPUT/$EXTENSION/ ; done
Antes de executar o comando acima, você precisará:
- Crie o diretório OUTPUT no diretório atual (
mkdir OUTPUT
) - Certifique-se de que não haja arquivos com nomes correspondentes em nenhum dos subdiretórios
Explicação
Primeiramente, o loop atribui à variável file
um arquivo da saída de find . -type f
. Exemplo de saída do find
comando está abaixo:
./a/myfile1.zip
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/myfile3.zip
./a/myfile4.zip
./a/myfile2.zip
A variável EXTENSION
é criada e seu valor é a file
variável com tudo até o último ponto removido. Assim ./a/myfile1.zip
se tornaria zip
.
O arquivo é então sincronizado (com detalhamento v
) para um diretório OUTPUT
nomeado após a extensão do arquivo.
Um exemplo da minha árvore de arquivos após executar este comando em algum teste:
./a
./a/b
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/b/c
./a/myfile1.zip
./a/myfile2.zip
./a/myfile3.zip
./a/myfile4.zip
./b
./b/c
./b/c/d
./b/c/file1.txt
./b/c/file2.txt
./b/c/file3.txt
./b/c/file4.txt
./c
./c/d
./c/d/e
./c/d/e/afile1.rar
./c/d/e/afile2.rar
./c/d/e/afile3.rar
./c/d/e/afile4.rar
./OUTPUT
./OUTPUT/rar
./OUTPUT/rar/afile1.rar
./OUTPUT/rar/afile2.rar
./OUTPUT/rar/afile3.rar
./OUTPUT/rar/afile4.rar
./OUTPUT/txt
./OUTPUT/txt/adoc1.txt
./OUTPUT/txt/adoc2.txt
./OUTPUT/txt/adoc3.txt
./OUTPUT/txt/adoc4.txt
./OUTPUT/txt/file1.txt
./OUTPUT/txt/file2.txt
./OUTPUT/txt/file3.txt
./OUTPUT/txt/file4.txt
./OUTPUT/zip
./OUTPUT/zip/myfile1.zip
./OUTPUT/zip/myfile2.zip
./OUTPUT/zip/myfile3.zip
./OUTPUT/zip/myfile4.zip
Responder2
Isto pode ser feito de forma muito simples comencontrar, conforme sugerido corretamente por Alex: assumindo que o diretório para procurar arquivos é/caminho1/para/algum/dire você deseja que os arquivos sejam movidos para/caminho2/para/outro/dir/txte assim por diante,
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir${0##*.}; [ -d $MYDIR ] && mv $0 $MYDIR || mv $0 /path3/to/miscellanea' {} \;
Este comando primeiro encontra todos os arquivos (-tipo f) contido no diretório/caminho1/para/algum/dire todos os seus subdiretórios, então passa o nome de cada arquivo ({}) para um pequeno bash de duas linhas, que primeiro extrai a extensão do nome do arquivo (referido comoUS$ 0dentro do bash) e o atribui à variável shell localMEUDIR, entãotestespela existência de um diretório adequado (se não existir tal diretório, talvez tenhamos cometido um erro) e se o diretório existir (&& ...) ele move o arquivo para o diretório apropriado, caso contrário (||...) coloca o arquivo em um local padrão,/caminho3/para/diversos.
O acima pressupõe que você já criou os diretórios necessários,/caminho2/para/outro/dir/txte assim por diante. Se, em vez disso, você quiser criá-los em qualquer lugar, você terá que modificar o acima como:
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir/${0##*.}; mkdir -p $MYDIR && mv $0 $MYDIR' {} \;