Provavelmente isso é muito simples, mas não consigo descobrir. Eu tenho uma estrutura de diretórios como esta (dir2 está dentro de dir1):
/dir1
/dir2
|
--- file1
|
--- file2
Qual é a melhor maneira de 'achatar' essa estrutura do diretor de forma a obter o arquivo1 e o arquivo2 no diretório1 e não no diretório2.
Respostas:
Você pode fazer isso com o GNU
find
e o GNUmv
:Basicamente, da maneira que funciona, se isso
find
percorre toda a árvore de diretórios e para cada arquivo (-type f
) que não está no diretório de nível superior (-mindepth 2
), ele executa ummv
para movê-lo para o diretório que você deseja (-exec mv … +
). O-t
argumento paramv
permite especificar o diretório de destino primeiro, o que é necessário porque a+
forma de-exec
coloca todos os locais de origem no final do comando. O-i
fazmv
perguntar antes de substituir quaisquer duplicatas; você pode substituir-f
para substituí-los sem perguntar (ou-n
não perguntar ou substituir).Como Stephane Chazelas aponta, o acima funciona apenas com ferramentas GNU (que são padrão no Linux, mas não na maioria dos outros sistemas). O seguinte é um pouco mais lento (porque chama
mv
várias vezes), mas muito mais universal:fonte
-exec +
para que ele não executa um grande número de processos demv
mv
precisa do destino como argumento final, mas + teria as fontes como argumento final. A descoberta nem aceita a sintaxe para a qual você a alterou (find: missing argument to `-exec'
)mv
tenha um-t
que possamos usar, então vou mudar para isso.find
imprime arquivos ocultos (pontos) por padrão. A profundidade é relativa ao diretório que você passa para encontrar.find ./dir -mindepth 2 -type f -exec mv -f '{}' ./dir ';'
se substituir duplicatasNo zsh:
**/
atravessa subdiretórios recursivamente. O qualificador global.
corresponde apenas aos arquivos regulares eD
garante que os arquivos de ponto sejam incluídos (por padrão, os arquivos cujo nome começa com a.
são excluídos das correspondências curinga). Para limpar os diretórios agora vazios posteriormente, executermdir dir1/**/*(/Dod)
-/
restringe-se aos diretórios eod
ordena primeiro a profundidade das correspondências para removerdir1/dir2/dir3
antesdir1/dir2
.Se o comprimento total dos nomes dos arquivos for muito grande, você poderá ter uma limitação no comprimento da linha de comando. O Zsh criou
mv
ermdir
não é afetado por esta limitação: executezmodload zsh/files
para habilitá-los.Com apenas ferramentas POSIX:
ou (mais rápido porque não precisa executar um processo separado para cada arquivo)
fonte
Tente fazer isso:
ou para cada arquivo correspondente
file[0-9]*
ao subdir:Veja http://mywiki.wooledge.org/glob
fonte
{}
no meu problema real.Eu escrevi duas funções que você pode usar juntas para fazer exatamente isso; você pode limitar o nível do diretório adicionando um
-maxdepth $VAL
parâmetro.fonte
Expandindo a resposta popular para essa pergunta, já que eu tinha um caso de uso para achatar um diretório contendo arquivos com o mesmo nome.
Nesse caso, a opção
-i
(--interactive
) passada paramv
não produziria o resultado desejado para nivelar a estrutura de diretórios e lidar com conflitos de nomes. Portanto, é simplesmente substituído por--backup=t
(equivalente a--backup=numbered
). Mais documentação sobre a opção-b
(--backup
) disponível em https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options .Resultando em:
Qual produz:
fonte
tar e zip têm a capacidade de incorporar e, em seguida, remover uma estrutura de diretório, então eu pude nivelar rapidamente um diretório aninhado com
tar -cvf all.tar *
seguida movendo all.tar para um novo local e, em seguida,
tar -xvf all.tar --strip=4
fonte