Eu tenho um diretório foo
com vários arquivos:
.
└── foo
├── a.txt
└── b.txt
e quero movê-lo para um diretório com o mesmo nome:
.
└── foo
└── foo
├── a.txt
└── b.txt
Atualmente, estou criando um diretório temporário bar
, mude foo
para bar
e renomeie bar
para foo
depois:
mkdir bar
mv foo bar
mv bar foo
Mas isso parece um pouco complicado e eu tenho que escolher um nome para bar
isso que ainda não foi escolhido.
Existe uma maneira mais elegante ou direta de conseguir isso? Estou no macOS se isso importa.
Para criar com segurança um diretório temporário no diretório atual, com um nome que ainda não foi usado, você pode usar
mktemp -d
assim:O
mktemp -d
comando criará um diretório no caminho fornecido, com oX
-es no final do nome do caminho substituído por caracteres alfanuméricos aleatórios. Ele retornará o caminho do diretório que foi criado e armazenamos esse valor emtmpdir
. 1Essa
tmpdir
variável pode ser usada ao seguir o mesmo procedimento que você já está fazendo,bar
substituída por"$tmpdir"
:O
unset tmpdir
no final apenas remove a variável.1 Normalmente, deve - se ser capaz de definir a
TMPDIR
variável de ambiente para um caminho de diretório onde se deseja criar arquivos ou diretórios temporários commktemp
, mas o utilitário no macOS parece funcionar sutilmente diferente em relação a isso do que o mesmo utilitário em outros sistemas BSD, e criará o diretório em um local totalmente diferente. O acima, no entanto, funcionaria no macOS. Usar o um pouco mais convenientetmpdir=$(TMPDIR=$PWD mktemp -d)
ou mesmotmpdir=$(TMPDIR=. mktemp -d)
só seria um problema no macOS se o diretório temporário padrão estivesse em outra partição e ofoo
diretório contivesse muitos dados (ou seja, seria lento).No macOS, você pode instalar o
rename
comando (um script Perl) usando o Homebrew:Em seguida, usando o
-p
(a lamkdir
) para fazer os diretórios necessários e-A
adicionar um prefixo:Execute com
-n
para mostrar as alterações sem renomear (dry-run):Se você tiver arquivos de ponto, para que um simples
*
não os pegue, use outros métodos comrename
:Com o bash, use (mal)
GLOBIGNORE
para*
combinar arquivos de ponto:Ou use
find
com-print0
erename
com-0
:Contanto que o conteúdo não seja suficiente para exceder os limites máximos dos parâmetros (e você não se importa com uma mensagem de erro "aceitável"), não precisa ser mais complicado do que isso:
Alteração para lidar com arquivos ocultos:
Sugiro o contrário. Não mova o diretório, mas apenas seu conteúdo:
Se você tem bash, você também pode fazer
(conforme descrito aqui ) para evitar a execução de ls e grep.
A vantagem desta solução é que é muito simples.
Desvantagens (como apontado nos comentários):
ls -A
conserta, mas nãols -a
)mv "$(ls | grep -v '^foo$')" foo
A maioria das desvantagens pode ser abordada usando algum truque bash, mas se for necessário lidar com nomes de arquivos malucos, é melhor usar uma abordagem mais robusta, conforme descrito em outras respostas.
Você já acertou em cheio. Você pode escolher um nome diferente para o diretório transitório, como o nome de destino com a data/hora atual em nanossegundos e nosso PID como um sufixo composto, mas isso ainda pressupõe que o diretório ainda não existe:
Se você quiser uma solução robusta garantida, eu faria um loop
mkdir
até que fosse bem-sucedidoVocê precisa fazer cd no diretório onde está a pasta de origem (foo).
Em seguida, execute o comando acima. Ele criará uma pasta chamada com o mesmo nome e moverá o conteúdo do pai foo para o diretório filho (exceto o diretório filho, daí a designação !).
Se o diretório filho foo já existir, você pode ignorar a primeira parte e apenas executar o comando mv:
No MacOS, você pode precisar definir a opção extglob:
Além das sugestões acima, você pode querer fazer check-out do rsync. Antes mesmo de começar, lembre-se sempre de usar a
--dry-run
opção com rsync antes de executá-la sem ele. O--dry-run
vai dizer o que aconteceria na vida real.O rsync tem muitas opções que podem não apenas ajudar a copiar/mover arquivos, mas também acelerar o processo. Aqui está uma maneira de fazer o seu trabalho. A
--remove-source-files
opção exclui os arquivos da fonte após o processo de movimentação (que na verdade é uma cópia seguida de uma exclusão). Observe que o comando rsync primeiro lê o conteúdo de foo, cria o diretório foo dentro do diretório existente chamado foo e inicia o processo de cópia. Ele termina com a exclusão dos arquivos de origem em foo. Cuidado: Preste atenção especial às barras para os nomes dos diretórios.Existem outras considerações, como muitos apontaram acima (como links simbólicos), mas a
man rsync
ajudará você a escolher as opções necessárias. Uma nota aqui: Como você solicitou uma solução para arquivos, isso funcionará. Isso não removerá os diretórios vazios que serão deixados para trás. Não conheço uma maneira de fazer isso sem uma etapa adicional, portanto, se alguém puder adicionar isso, obrigado antecipadamente!a = modo de arquivo
v = verboso
Simplesmente não toque em foo e você não terá problemas com nomes idênticos. Em vez disso, crie um diretório com o mesmo nome dentro dele e mova tudo para lá. Use o truque $_ para isso e && para torná-lo uma linha:
Isso lançará um erro inofensivo ( mv: rename foo to foo/foo: Invalid argument ) que você pode ignorar.
Vantagem sobre outras respostas: você só precisa digitar o nome do diretório uma vez, para não cometer erros de digitação.
você pode misturar isso com outras respostas para um efeito ainda melhor:
mv {.,}* $_
cuidará de arquivos ocultos (ao custo de mais erros que você também pode ignorar)mv ./!(foo)
evitará a mensagem de erro, mas somente se você definirshopt -s extglob
Na verdade, isso é enganosamente simples e estou chocado que ninguém mais ofereceu essa resposta ainda, então aqui vou eu usando o seguinte, por exemplo ...
Agora vem a parte mágica
Agora, por que isso funciona? Não posso dar a resposta mais precisa, pois sou apenas um neófito - mas entendo que se resume a como os
/
caracteres à direita são tratados nas pastas.Olhe atentamente para o comando mv
$ mv ./bar/foo ./foo/
Observe como a pasta de destino dos arquivos é especificada sem um final
/
, enquanto o destino que compartilha o nome da pasta de destino foi especificado usando um final/
'. Este é o seu bilhete mágico e pode mordê-lo na bunda se você não estiver prestando atenção.Lamento não poder oferecer uma resposta mais elaborada do que essa no momento, mas talvez alguém com mais conhecimento fluente tome a liberdade de editar minha resposta.
De qualquer forma, esta parece ser a solução mais simples e direta, com um único uso do
ls
comando e sem criação de pastas intermediárias.Espero que funcione para você, abraços!