Como faço para que o mv (ou o * curinga) mova arquivos ocultos?

133

Estou migrando meu diretório pessoal de um sistema antigo para um novo, e o arquivo tar que criei contém tudo, incluindo arquivos ocultos, como .bashrc. No entanto, quando movo o conteúdo do tarball descompactado (que está em / tmp) para o meu novo diretório inicial, os arquivos ocultos não são copiados ( mv /tmp/home/rcook/* /home/rcook/). Como faço para que o mv os mova?

Na verdade, acho que o problema não é com o mv, mas com o brilho do bash. Se eu fizer isso:

mkdir a
mkdir b
touch a/.foo
touch a/bar
mv a/* b/
ls -a a/ b/

Eu vejo isso:

a/:
.  ..  .foo

b/:
.  ..  bar

a/.foonão se moveu. Então, como posso obter o curinga * para encontrar arquivos ocultos?

Sim, suponho que eu poderia descompactar o tarball diretamente no meu diretório pessoal, mas o tarball se descompacta home/rcook/...e quero ter certeza de substituir o novo .bashrcetc. pelas versões antigas e personalizadas e saber como encontrar e mover arquivos ocultos é uma habilidade que vale a pena. Sugestões?


Algumas respostas sugerem fazer algo parecido mv src/.* dest/. No entanto, tentei isso nos meus diretórios de teste e obtive erros. Começando com:

rcook$ ls -a a/ b/
a/:
.  ..  bar  .foo

b/:
.  ..
rcook$ mv a/.* b/
mv: cannot move 'a/.' to 'b/.': Device or resource busy
mv: cannot remove 'a/..': Is a directory
rcook$ ls -a a/ b/
a/:
.  ..  bar

b/:
.  ..  .foo

O que estou fazendo errado?

Randall Cook
fonte

Respostas:

146

Você consegue fazer isso :

shopt -s dotglob
mv /tmp/home/rcook/* /home/rcook/

Você pode colocar

shopt -s dotglob

no seu ~/.bashrcse você quiser que seja o padrão.

Veja http://mywiki.wooledge.org/glob


Outra abordagem para copiar os arquivos de ponto:

mv /tmp/home/rcook/.[!.]* /home/rcook/

Não use o padrão ..*conforme ele corresponder ..(ponteiro para o diretório pai). Se houver arquivos cujo nome comece com dois pontos ( ..something), use também o padrão ..?*.

Gilles Quenot
fonte
Confira as adições que coloquei na parte inferior da minha pergunta. Obrigado.
Randall Cozinhe
1
Nada está errado .e ..são dirs especiais: respectivamente dir atual e dir pai . É apenas um aviso. shopt -s dotglobSolução de melhor uso
Gilles Quenot
Acabei fazendo apenas dois movimentos: mv home/rcook/* /home/rcook/seguidos por mv home/rcook/.* /home/rcook/. Isso fez o truque, embora eu desejasse ter seguido o link e lido primeiro sobre o modo dotglob. Isso teria me poupado um passo. 1
Randall Cook
Então a segunda abordagem requer o uso de caminhos absolutos?
franzlorenzon
3
Se você estiver usando zsh, poderá usar o Dqualificador de globbing ou a GLOB_DOTSopção de shell .
mgalgs
43

Nas adições, você tem erros, mas o código ainda funciona. A única coisa a acrescentar é que você disse apenas para copiar os arquivos de ponto. Experimentar:

mv src/* src/.* dst/

Você ainda receberá os erros para o. e .. entradas, o que é bom. Mas a mudança deve ter sucesso.

~/scratch [andrew] $ mv from/* from/.* to/
mv: cannot move from/.’ to to/.’: Device or resource busy
mv: cannot remove from/..’: Is a directory
~/scratch [andrew] $ ls -a from/ to/
from/:
.  ..

to/:
.  ..  test  .test
Andrew Schwartz
fonte
1
Bons pontos, @AndrewSchwartz. Eu também gosto dessa abordagem. Eu acho que merece mais reconhecimento.
Randall Cook
Eu gosto da resposta de @Drake Clarris um pouco mais, porque estou executando o Amazon AWS CodeBuild e o código de retorno diferente de zero realmente fez com que minha compilação parasse. Acabei movendo o .hiddenarquivo que tinha explicitamente para resolver meu problema.
HeyWatchThis
Se o código de saída diferente de zero for um problema, você poderá suprimi-lo, por exemplo, anexando || :( ||significa executar o seguinte em falso / erro, :é o comando noop). Mas isso também suprimiria erros legítimos, por exemplo, a pasta de destino não existe. Não consigo encontrar uma maneira mais elegante mvde excluir as entradas .e ... Butt big plus para mim sobre cp não está gravando novos arquivos no disco.
Andrew Schwartz
10

Se você estiver ls -lem um diretório, verá .e ..entre os arquivos listados. Então, acho que mv .* /destleva esses indicadores em consideração. Experimentar:

mv /tmp/home/rcook/{*,.[^.]*,..?*} /home/rcook/

isso ignorará os ponteiros dir e pai atuais.

Você receberá um erro se qualquer um dos três padrões *, [^.]*ou ..?*corresponde nenhum arquivo, assim que você deve incluir apenas os que correspondem.

Azamat
fonte
Agradável. Uma resposta semelhante para esse estilo de globbing está aqui: superuser.com/a/784046/144977 . Obrigado por postar isso.
Phyatt #
7

Duas soluções possíveis em que consigo pensar. A primeira é usar cp em vez disso com sua opção recursiva, copiando o diretório atual para o destino.

cp -Rp . /desired/directory

então você pode remover os arquivos de origem no diretório atual

Como alternativa, se você souber que os arquivos têm um nome seguro (sem espaços, curingas, caracteres não imprimíveis), poderá fazer algo assim

mv $(ls -A) /desired/directory
Drake Clarris
fonte
4
Copiar e remover é muito diferente de mover se a origem e o destino estiverem no mesmo sistema de arquivos. Pelo menos inclua a opção -pde preservar os metadados. O uso lsdeve ser o último recurso, e aqui existem maneiras melhores e mais simples.
Gilles
2

Não existe realmente arquivos "ocultos" no Linux. Os arquivos que começam com um ponto estão ocultos das listagens de arquivos por padrão.

Para copiar arquivos mesmo com um glob, você precisa prefixar o arquivo .como mv -u .* fooe, em seguida, .fooserá exibido como foo/.fooquando movido.

A opção -u somente moverá os arquivos quando a fonte for mais nova ou o destino estiver ausente. Ou você pode simplesmente ignorar os erros sobre a movimentação .e ..como eles são arquivos especiais e não podem ser movidos, mas ficam presos na .*bola pelo shell.

dobey
fonte
Confira as adições que coloquei na parte inferior da minha pergunta. Obrigado.
Randall Cozinhe
0

Então nós temos:

a
|-- .foo
`-- bar

e:

b

Demorei bastante para encontrar uma solução melhor do que todas as respostas aqui.

Depois, levei 30 segundos para este comando:

$ mv --help

Então eu encontrei meu amor:

$ mv a/ b/ -T

Nota: Eu nem entendo o argumento -T. Apenas fiz o que eu precisava. Aqui diz:

-T, --no-target-directory trata o DEST como um arquivo normal

user433901
fonte
1
Se você omitir as barras, não será necessário -T. De qualquer maneira, isso está essencialmente dizendo ao mv para mover o próprio diretório, em vez de mover todos os arquivos de dentro dele.
thomasrutter
@ Thomashoutter, não é mover o diretório em si a mesma coisa que renomeá-lo?
Randall Cook
3
Sim, se o destino pai permanecer o mesmo, ele será renomeado. Seja como for, provavelmente não ajuda a responder à pergunta original, que era sobre mover os arquivos dentro do diretório para um determinado local.
thomasrutter
0

No meu caso, eu estava simplesmente tentando mvum único arquivo oculto e esta foi a solução:

FILE=.myHiddenFile
mv "$FILE" dest/

Explicação

No começo eu estava tentando:

mv .myHiddenFile dest/

Mas continuou produzindo o erro:

mv: cannot stat '.myHiddenFile': No such file or directory

Mesmo que um ls -almostrou que o arquivo e dest/existia.

O motivo parece ser porque o shell estava interpretando o "." no nome do arquivo, movendo-o para uma variável, evita a interpretação. Provavelmente existem outras maneiras de resolver isso, mas isso foi suficiente para nós.

Isaías
fonte
-1

Se você deseja copiar arquivos, incluindo arquivos ocultos, para o diretório atual em que está.

cp -Rp source-directory/. .
Rick
fonte
1
Isso é muito semelhante à resposta de Drake Clarris de 2013. Você tem mais alguma coisa a acrescentar?
Randall Cook