cp arquivos ocultos com padrões glob

13

Situação:

$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat ‘foo/*’: No such file or directory)

Eu tenho um diretório cheio de pastas e arquivos ocultos. O que está acontecendo e qual é a solução?

    
por Gradient 07.09.2013 / 09:06

5 respostas

17
Disclaimer: Esta resposta lida com o Bash especificamente, mas muito disso se aplica à questão relacionada aos padrões glob!

O caractere de estrela ( * ) é um caractere curinga. Há um certo conjunto de caracteres que tomará o lugar e o primeiro caractere sendo um ponto ( . ) não é um deles. Este é um caso especial apenas por causa do funcionamento dos sistemas de arquivos Unix, os arquivos que começam com um ponto são considerados "ocultos". Isso significa que ferramentas como cp , ls , etc. não as "verão", a menos que explicitamente instruído a fazê-lo.

Exemplos

Primeiro, vamos criar alguns dados de amostra.

$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}

Agora temos o seguinte:

$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
'-- regfile3

Agora vamos jogar alguns jogos. Você pode usar o comando echo para listar o que um curinga em particular ( * ) seria para um determinado comando da seguinte forma:

$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3


$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2

$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .dotdir*
.dotdir1 .dotdir2

Mudando o comportamento?

Você pode usar o comando shopt -s dotglob para alterar o comportamento de * , de modo que, além de arquivos como regfile1 , ele também corresponda a .dotfile1 .

trecho da página bash man

dotglob If set, bash includes filenames beginning with a '.' in the results 
        of pathname expansion.

Exemplo:

$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

Você pode reverter esse comportamento com este comando:

$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3

Sua situação?

Para você, você está dizendo a cp que deseja copiar todos os arquivos que correspondem ao padrão * e não há arquivos.

$ cp foo/.* .

Ou você pode fazer isso se quiser tudo na pasta foo :

$ cp foo .

Ou você pode ser explícito:

$ cp foot/.* foo/* .

Uma forma mais compacta usando a expansão de chave em bash :

$ cp foo/{.,}* .

A qualquer momento, você pode usar o truque echo para ver quais são os padrões de arquivo propostos (esse é o termo sofisticado do qual a estrela faz parte).

$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3

Aliás, se você vai copiar um diretório de arquivos + outros diretórios, você geralmente quer fazer isso de forma recursiva, essa é a -R que alterna para cp :

$ cp -R foo/. .
    
por 07.09.2013 / 10:09
21

Com o zsh , a maneira mais comum é usar o D qualificador glob (para incluir [D] ot files):

cp foo/*(D) .

Note que com ou sem D , os zsh globs nunca incluem . nem .. (como seria de esperar).

    
por 07.09.2013 / 16:57
4

O shell está tratando esses arquivos como oculto quando resolve o caractere * , portanto, cp não recebe nenhum desses nomes como argumentos.

Você pode copiá-los especificando explicitamente cp foo/.* .

    
por 07.09.2013 / 09:24
1

Se o que você deseja fazer é copiar todos os arquivos & diretórios de um lugar para outro, você poderia usar o comando padrão rsync . No exemplo que você deu acima:

mkdir foo && touch foo/.test
rsync -a foo/ .

copiará recursivamente todo o conteúdo de foo , incluindo arquivos ocultos e diretórios ocultos, para o diretório atual. A barra final no final de foo/ é importante para o rsync; com ele apenas o conteúdo de foo é copiado, sem que o rsync copie foo também. Por exemplo: -

mkdir src && mkdir dest && touch src/.test
rsync -a src  dest    // copies 'src' contents to 'dest/src'
rsync -a src/ dest    // copies 'src' contents to 'dest' 

Existem muitas outras opções disponíveis para ajustar o rsync, incluindo a cópia entre máquinas.

    
por 07.09.2013 / 16:53
1

A resposta do Stéphane Chazelas está correta para uma única glob. No entanto, se você quiser configurá-lo para todas as globs, você pode usar

setopt GLOB_DOTS

Coloque no seu ~/.zshrc para torná-lo permanente.

    
por 16.06.2017 / 08:50