Como você move todos os arquivos (inclusive ocultos) de um diretório para outro?

135

Como movo todos os arquivos em um diretório (incluindo os ocultos) para outro diretório?

Por exemplo, se eu tiver uma pasta "Foo" com os arquivos ".hidden" e "notHidden" dentro, como movo os dois arquivos para um diretório chamado "Bar"? O seguinte não funciona, pois o arquivo ".hidden" permanece em "Foo".

mv Foo/* Bar/

Tente você mesmo.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
Cory Klein
fonte
Bah, eu sabia que deveria ter atualizado as respostas antes de digitar as minhas. Link muito útil.
Steven D
Infelizmente, esta questão acabou aqui porque eu disse de forma que ele deve mover-se aqui ou SU, então é claro que se mudou para cá, quando houve uma duplicata no SU já :)
Michael Mrozek
Pessoalmente, acho que * nix perguntas e respostas específicas devem estar fora de tópico no SU. Com as regras atuais, acabamos com toneladas de colisões de conteúdo entre os dois - como esta questão.
Cory Klein

Respostas:

154

Zsh

mv Foo/*(DN) Bar/

ou

setopt -s glob_dots
mv Foo/*(N) Bar/

(Deixe de fora (N)se você sabe que o diretório não está vazio.)

Bater

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

Se você souber que o diretório não está vazio:

FIGNORE='.?(.)'
mv Foo/* Bar/

Padrão (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Se você deseja permitir que o mvcomando retorne um status de erro, embora tenha sido bem-sucedido, é muito mais simples:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find e GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Localização padrão

Se você não se importa de mudar para o diretório de origem:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

Aqui estão mais detalhes sobre como controlar se os arquivos de ponto são correspondidos no bash, ksh93 e zsh.

Bater

Defina a dotglobopção .

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

Há também a GLOBIGNOREvariável mais flexível , que você pode definir para uma lista separada por dois pontos de padrões curinga para ignorar. Se não dotglobestiver definido (a configuração padrão), o shell se comportará como se o valor estivesse vazio se estiver definido e como se o valor estivesse .*se a opção não estiver definida . Consulte Expansão do nome do arquivo no manual. Os diretórios difundidos .e ..sempre são omitidos, a menos que .correspondam explicitamente ao padrão.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

Defina a FIGNOREvariável . Se não estiver definido (a configuração padrão), o shell se comportará como se o valor fosse .*. Para ignorar .e .., eles devem ser correspondidos explicitamente (o manual no ksh 93s + 2008-01-31 declara isso .e ..sempre é ignorado, mas isso não descreve corretamente o comportamento real).

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

Você pode incluir arquivos de ponto em um padrão , correspondendo-os explicitamente.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

Para que a expansão saia vazia se o diretório estiver vazio, use a Nopção de correspondência de padrão: ~(N)@(*|.[^.]*|..?*)ou ~(N:*|.[^.]*|..?*).

Zsh

Defina a dot_globopção .

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.e ..nunca são correspondidos, mesmo se o padrão corresponder .explicitamente à liderança .

% echo .*
..two .one

Você pode incluir arquivos de ponto em um padrão específico com o D qualificador glob .

% echo *(D)
..two .one none zero

Adicione o Nqualificador glob para fazer a expansão sair vazia em uma pasta vazia: *(DN).


Nota: você pode obter resultados de expansão de nome de arquivo em ordens diferentes (por exemplo, noneseguido por .oneseguido por ..two) com base nas definições das LC_COLLATE, LC_ALLe LANGvariáveis.

Gilles
fonte
1
Por que nullglob? Faria mais sentido abortar o mvcomando (como fish, csh / tcsh, zsh (sem (N)) do ou bash com failglob) do que executar um mv /Bar/comando que faz pouco sentido.
Stéphane Chazelas
1
Eu diria que sua descrição do GLOBIGNORE é imprecisa e enganosa. Definir GLOBIGNORE para um valor não vazio se transforma em dotglob e faz que .e ..nunca são combinados (como em outras cascas sensíveis como zsh, peixe, pdksh e derivados), mesmo se você virar dotglob recuar depois. ( GLOBIGNORE=:; shopt -u dotglob; echo .*não será exibido .e ..). definindo GLOBIGNORE para .:..ou .ou :ter o mesmo efeito.
Stéphane Chazelas
ksh93sempre ignorando .e ..parece ter sido interrompido entre ksh93k+(onde funcionou) e ksh93m(onde não funciona mais). Observe que é ruim, pois ksh93terá o valor de FIGNORE do ambiente, portanto, uma variável de ambiente, FIGNORE='!(..)'por exemplo, pode causar estragos.
Stéphane Chazelas
24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

De man bash

dotglob Se definido, o bash inclui nomes de arquivos começando com um '.' nos resultados da expansão do nome do caminho.

SiegeX
fonte
Com a ressalva de que esse comando retornará um código de erro se o diretório estivesse vazio (mesmo que o comando tenha sido executado como pretendido).
Gilles
1
@Gilles, o erro será então ao mvreclamar que esse arquivo chamado Foo/*não existe. Curiosamente, se Foofor pesquisável, mas não legível, e houver um arquivo chamado *lá, você não receberá nenhum erro, esse arquivo será movido, mas não os outros no diretório. bashtem uma failglobopção para que ele se comporta mais como zsh, fishou csh/ tcshe abortar o comando com um erro quando uma bola não pode ser expandido em vez de que o comportamento falso de deixar o glob como está.
Stéphane Chazelas 22/02
8

Uma maneira simples de fazer isso bashé

mv {Foo/*,Foo/.*} Bar/

Mas isso também moverá diretórios.

Se você deseja mover todos os arquivos, incluindo ocultos, mas não deseja mover nenhum diretório, use um loop for e teste.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;

Mês Boris
fonte
4

Uma maneira é usar find:

find Foo/ -type f -exec mv -t Bar/ {} \+

O -type frestringe o comando find para encontrar arquivos. Você deve investigar o -type, -maxdepth, e -mindepthopções de findpersonalizar o seu comando para conta para subdiretórios. O Find tem uma página de manual longa, mas muito útil .

Steven D
fonte
3
Isso move apenas os arquivos regulares Foo/, não os subdiretórios e outros arquivos.
Gilles
2

Experimente o comando copy cp:

$ cp -r myfolder/* destinationfolder

cp -r significa copiar recursiva, para que todas as pastas e arquivos sejam copiados.

Você pode usar o comando rmremover para remover uma pasta:

$ rm -r myfolder

Veja mais: mova todos os arquivos de um diretório para outro .

ucefkh
fonte
2
Não é o melhor quando você está movendo muitos arquivos grandes, mas acho que funcionaria.
Cory Klein
Talvez se você usar um ponto em vez da estrela?
vincent
1

Rsync é outra opção:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Isso funciona porque no rsync a barra final importa, sourcedirectory/refere-se ao conteúdo do diretório, enquanto sourcedirectoryse refere ao próprio diretório.

A desvantagem desse método é que o rsync apenas limpará os arquivos após a movimentação, não o diretório. Então você fica com uma árvore de diretórios vazia. Para soluções alternativas para isso, consulte:

Mover arquivos e excluir diretórios com o rsync?

Portanto, embora isso possa não ser ideal para operações de movimentação, pode ser extremamente útil para operações de cópia.

Grumbel
fonte
1

Resposta para bash / fish

Aqui está uma maneira de fazer isso usando curingas:

.[!.]* ..?*corresponderá a todos os arquivos ocultos, exceto .e..

.[!.]* ..?* *corresponderá a todos os arquivos (ocultos ou não), exceto .e..

E para responder ao exemplo específico desta pergunta, você precisa cd foo && mv .[!.]* ..?* * ../bar

Explicação

.[!.]*corresponde aos nomes de arquivo que começam com um ponto, seguido por qualquer caractere, exceto o ponto seguido opcionalmente por qualquer sequência. Está perto o suficiente, mas falta arquivos começando com dois pontos ..foo. Para incluir esses arquivos, adicionamos o ..?*que corresponde aos nomes dos arquivos começando com dois pontos, seguidos por qualquer caractere, opcionalmente seguido por qualquer sequência.

Teste

Você pode testar esses curingas com os comandos abaixo. Eu tentei-os com sucesso em bash e peixe. Eles falham sob sh, zsh, xonsh.

mkdir temp
cd temp
touch  a  .b  .bc  ..c  ..cd  ...d  ...de
ls .[!.]* ..?*
# you get this output:
          .b  .bc  ..c  ..cd  ...d  ...de
# cleanup
cd ..
rm -rf temp
ndemou
fonte
0

Você também pode encontrar e grep com aspas para selecionar arquivos para o comando move. Passe-os para mv.

Ou seja, para arquivos ocultos

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

assim

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

Move apenas os arquivos ocultos selecionados para Bar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

Move todos os arquivos em Foo para Bar desde o '.' no comando egrep atua como um curinga sem os colchetes.

O ^personagem garante que a partida comece do início da linha.

Alguns detalhes da egrepcorrespondência de padrões podem ser encontrados aqui .

O uso de maxdepth 1stops find de entrar em subdiretórios.

user3192145
fonte
0

Inspirado nesta resposta :

Sem copiar os arquivos ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Ressalvas:

  • --link-destO caminho deve ser absoluto ou relativo a DESTINATION ( Bar no exemplo)

  • Você deve colocar /depois de SOURCE ( Foo/no exemplo), caso contrário, ele copiará a pasta SOURCE em vez do conteúdo dela.

palindrom
fonte
0

Acho que isso funciona bem para o bash e não há necessidade de alterar as opções do shell

mv sourcedir/{*,.[^.]*} destdir/

EDITAR:

Então, como G-man afirmou, minha resposta original não é compatível com posix e é praticamente a mesma que a resposta de ndemou acima, com uma alteração, que é usar a expansão de chaves para criar listas de strings que são executadas. Isso significa apenas que você não precisa cdentrar no diretório de origem. Não é realmente uma grande mudança, mas é diferente.

exemplo: digamos que você já tenha o seguinte layout.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

A pergunta original mencionava apenas arquivos ocultos com um único período, mas digamos que há alguns com dois ou mais períodos no início do nome. Você pode apenas adicionar uma expressão adicional aos chavetas. Podemos então executar

mv sourcedir/{*,.[!.]*,..?*} destdir/

Isso é expandido para o seguinte:

mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/

Agora você deve ver todos os arquivos localizados no destdir :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

Você pode fazer algumas coisas bem legais com chaves no bash com ainda mais adições no 4.x. Confira bash-hackers para alguns exemplos bacanas.

cmndr sp0ck
fonte
1
Isso basicamente duplica a resposta de ndemou, exceto que você adicionou chaves (sem explicá-las). Mas (1) sua resposta não corresponde aos arquivos cujos nomes começam com ..(2) para ser compatível com POSIX , você deve usar em !vez de ^; ou seja,  {*,.[!.]*}.
G-Man
@ G-Man, desculpe por isso. Então você está correto e meu mal por não ter visto a resposta de ndemou. Eles são praticamente a mesma coisa. 1. obrigado por apontar que minha versão não é compatível com posix. 2. Estou usando a expansão de chaves para criar listas de strings nas quais o shell usará para executar uma ação. Isso também significa que não preciso cdentrar no diretório de origem para atuar nos arquivos ou escrever os mesmos caminhos repetidamente para expressar os caminhos de todos os arquivos. Atualizarei o exemplo em breve para fornecer a qualquer leitor uma imagem melhor do que estou falando.
cmndr sp0ck 7/03
0

Para distribuições mínimas de Linux, o seguinte deve funcionar. Primeiro, execute uma movimentação básica geral (que perde os arquivos ocultos). Em seguida, mova todos os arquivos ocultos (incluindo .oe ..que não serão realmente movidos).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Notas: Se não houver conteúdo visível, o primeiro comando produzirá uma mensagem de erro. O segundo comando sempre produzirá um erro dizendo que não pode se mover .e ... Como tal, basta canalizar os erros /dev/null(como mostrado).

Se você precisar disso como uma linha, basta combiná-los com um ponto e vírgula:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
BuvinJ
fonte