Como mover todos os arquivos, incluindo arquivos ocultos para o diretório pai via *

113

Deve ser uma pergunta popular, mas não consegui encontrar uma resposta.

Como mover todos os arquivos via * incluindo arquivos ocultos, bem como para o diretório pai, como este:

mv /path/subfolder/* /path/

Isso moverá todos os arquivos para o diretório pai como esperado, mas não moverá os arquivos ocultos. Como fazer isso?

TroodoN-Mike
fonte
1
esta pergunta tem uma duplicata no SU , com uma resposta ainda mais correta (porém não a aceita): cp -r /path/to/source/. /destination
Florian

Respostas:

202

Você pode encontrar um conjunto abrangente de soluções para isso na resposta do UNIX e Linux para Como você move todos os arquivos (incluindo os ocultos) de um diretório para outro? . Ele mostra soluções em Bash, zsh, ksh93, padrão (POSIX) sh, etc.


Você pode usar esses dois comandos juntos:

mv /path/subfolder/* /path/   # your current approach
mv /path/subfolder/.* /path/  # this one for hidden files

Ou todos juntos ( obrigado pfnuesel ):

mv /path/subfolder/{.,}* /path/

Que se expande para:

mv /path/subfolder/* /path/subfolder/.* /path/

(exemplo: echo a{.,}bexpande para a.b ab)

Observe que isso mostrará alguns avisos:

mv: cannot move ‘/path/subfolder/.’ to /path/.’: Device or resource busy
mv: cannot remove /path/subfolder/..’: Is a directory

Basta ignorá-los: isso acontece porque /path/subfolder/{.,}*também se expande para /path/subfolder/.e /path/subfolder/.., que são o diretório e o diretório pai (consulte O que significam “.” E “..” quando em uma pasta? ).


Se você quiser apenas copiar, você pode usar um mero:

cp -r /path/subfolder/. /path/
#                     ^
#                     note the dot!

Isso irá copiar todos os arquivos, normais e ocultos, desde que se /path/subfolder/.expanda para "tudo deste diretório" (Fonte: Como copiar com cp para incluir arquivos ocultos e diretórios ocultos e seus conteúdos? )

fedorqui 'então pare de prejudicar'
fonte
2
As chaves são apenas um atalho mv /path/subfolder/* /path/subfolder/.* /path/, não sendo estritamente necessário para combinar os dois comandos em um.
chepner de
7
Recebo o seguinte erro:mv: overwrite `/path/.'? y mv: cannot move `/path/subfolder/.' to `/path/.': Device or resource busy mv: overwrite `/path/..'? y mv: cannot move `/path/subfolder/..' to `/path/..': Device or resource busy
Dejan
@Dejan Apenas ignore. .denota o diretório atual e ..denota o updiretório. Você deve ter notado que todos os outros arquivos foram movidos.
Debiprasad de
Vale a pena mencionar que o atalho de chaves não funcionará para todos os shells, mas o comando @chepner acho que sim
Jesús Carrera
7
"Simplesmente ignore o aviso" pode nem sempre ser uma boa ideia. No momento, estou tendo um problema com um script em que preciso interromper a execução se alguma etapa falhar - como essa solução sempre causa um erro, ela mata meu script. Preciso de uma maneira de determinar se o comando mv falhou ou não ...
MarioVilas
29

Acho que este é o mais elegante, pois também não tenta se mover ..:

mv /source/path/{.[!.],}* /destination/path
Vanderstaaij
fonte
1
sim eu percebi isso dando aquelas mensagens de erro também, bom achado.
Joseph Astrahan
Acho que essa é uma solução muito boa, mas é meio difícil de lembrar esse padrão
Dylan B
isso iria perder arquivos como ..anythingou ...anythingetc. - stackoverflow.com/a/31438355/2351568 contém o regex correto para este problema. || mas mesmo assim, usar shopt -s dotglobainda é a melhor solução!
DJCrashdummy
@DylanB não memoriza. lembre-se de que ele corresponde a tudo o que está entre chaves, separados por vírgulas. {a,b}*encontraria todos os arquivos começando com a ou b, como "anatomia" e "bulldozer". A segunda correspondência é apenas uma correspondência vazia, equivalente a *, e a primeira correspondência é equivalente a .[!.], onde o grupo [!.]significa um grupo que NÃO começa com a .. Isso significa, .*mas não ..*.
mazunki,
28

Isso moverá todos os arquivos para o diretório pai como esperado, mas não moverá os arquivos ocultos. Como fazer isso?

Você pode ligar dotglob:

shopt -s dotglob               # This would cause mv below to match hidden files
mv /path/subfolder/* /path/

Para desligar dotglob, você precisa dizer:

shopt -u dotglob
Devnull
fonte
Muito útil. Queria saber mais, mas o shopt é embutido, portanto man shoptnão funciona e help shopté muito breve. Mas você pode fazer bashman () { man bash | less -p "^ $1 "; }e, em seguida, bashman shoptler tudo sobre isso diretamente. (Pode ser necessário apertar n para pular para o comando se houver linhas começando com shopt, como descobri.)
Nick Rice
2
isso também afetará todos os outros comandos como ls.. portanto, não é realmente o que você deseja, provavelmente
phil294
5

Uma solução alternativa mais simples é usar o rsyncutilitário:

sudo rsync -vuar --delete-after --dry-run path/subfolder/ path/

Nota: o comando acima mostrará o que será alterado. Para executar as mudanças reais, remova--dry-run .

A vantagem é que a pasta original ( subfolder) seria removida, bem como parte do comando, e ao usar mvexemplos aqui você ainda precisa limpar suas pastas, sem mencionar dor de cabeça adicional para cobrir arquivos ocultos e não ocultos em um único padronizar.

Além disso, rsyncoferece suporte para copiar / mover arquivos entre controles remotos e garantir que os arquivos sejam copiados exatamente como eram originalmente ( -a).

O -uparâmetro usado ignoraria os arquivos mais recentes existentes, -rrecursaria nos diretórios e -vaumentaria o detalhamento.

Kenorb
fonte
Melhor solução de todas! No meu caso, acabei de remover o parâmetro -u, porque não gostaria de atualizar a pasta raiz. Obrigado
Thales Ceolin
Este é um daqueles comandos onde se você não tomar cuidado, você pode realmente bagunçar as coisas para você mesmo no Linux, permanentemente. Por favor, atualize sua resposta para incluir sudo antes do comando rsync, caso contrário, os usuários podem facilmente obter Permissão Negada para mkdir, mas as exclusões de arquivos continuarão, portanto, o comando rsync excluirá todo o diretório que você deseja mover e não fará mais nada . Você perderá todo o seu diretório. Depois de adicionar sudo à sua resposta, essa provavelmente será a resposta aceita. Portanto, o comando deve ser: sudo rsync -vuar --delete-after path / subfolder / path /
Blue Water
@JohnnyB Desculpe pelo transtorno. Eu adicionei sudoe --dry-run, para que as pessoas possam testar as alterações antes de executar o comando real para evitar qualquer confusão em potencial.
Kenorb
Oh, eu não sabia que havia uma opção --dry-run. Boa adição. Não há necessidade de desculpas. Isto e excelente.
Água Azul
3

Deixe-me apresentá-lo ao meu amigo "dotglob". Liga e desliga se "*" inclui ou não arquivos ocultos.

$ mkdir test
$ cd test
$ touch a b c .hidden .hi .den
$ ls -a
. ..  .den  .hi .hidden a b c

$ shopt -u dotglob
$ ls *
a b c
$ for i in * ; do echo I found: $i ; done
I found: a
I found: b
I found: c

$ shopt -s dotglob
$ ls *
.den  .hi .hidden a b c
$ for i in * ; do echo I found: $i ; done
I found: .den
I found: .hi
I found: .hidden
I found: a
I found: b
I found: c

O padrão é "desligado".

$ shopt dotglob
dotglob         off

É melhor ligá-lo novamente quando terminar, caso contrário, você confundirá as coisas que presumem que estará desligado.

TomOnTime
fonte
3

Usando o findcomando em conjunto com o mvcomando, você pode evitar que o mvcomando tente mover diretórios (por exemplo, ..e .) e subdiretórios. Aqui está uma opção:

find /path/subfolder -maxdepth 1 -type f -name '*' -exec mv -n {} /path \;

Existem problemas com algumas das outras respostas fornecidas. Por exemplo, cada um dos seguintes tentará mover subdiretórios do caminho de origem:

1) mv /path/subfolder/* /path/ ; mv /path/subfolder/.* /path/
2) mv /path/subfolder/{.,}* /path/ 
3) mv /source/path/{.[!.],}* /destination/path

Além disso, 2) inclui o. e .. arquivos e 3) perder arquivos como ..foobar, ... barfoo, etc.

Você poderia usar mv /source/path/{.[!.],..?,}* /destination/path,, que incluiria os arquivos perdidos por 3), mas ainda tentaria mover subdiretórios. Usar o findcomando com o mvcomando descrito acima elimina todos esses problemas.

teancum144
fonte
2

Minha solução para este problema quando tenho que copiar todos os arquivos (incluindo .arquivos) para um diretório de destino mantendo as permissões é: (sobrescrever se já existir)

yes | cp -rvp /source/directory /destination/directory/

yesé para sobrescrever arquivos de destino automaticamente, rrecursivo, vdetalhado, pretém permissões.

Observe que o caminho de origem não termina com um/ (portanto, todos os arquivos / diretório e arquivos .são copiados)

O diretório de destino termina com,/ pois estamos colocando o conteúdo da pasta de origem no destino como um todo.

Rajneesh Gadge
fonte
Embora yesseja um comando incrível para usar se você deseja substituir os arquivos de destino, nem sempre é desejado. Use-o apenas se tiver certeza de que deseja fazer isso. Além disso, há uma diferença entre yes | cp ...e cp -f ...?
mazunki