Em bash
, sem a opção dotglob
, os arquivos ocultos são ignorados, a menos que o glob explicitamente (que é um líder literal .
) os solicite. E .
e ..
não são ignorados (ao contrário do que os shells mais sensatos gostam de pdksh
, zsh
ou fish
do).
Com dotglob
, apenas .
e ..
são ignorados, a menos que a glob comece com .
.
Com extglob
, bash
adiciona suporte a alguns dos operadores% glob extendido deksh
. No entanto, aqui com um bug / misfeature quando se trata de !(...)
one.
Em ksh
(embora não pdksh
) e bash
, @(.*)
é um caso em que você solicita explicitamente os dotfiles (embora a documentação não deixe isso claro).
Mas em !(.git)
você não está solicitando dotfiles. ksh
e zsh
in ksh
emulation lidam com isso corretamente, mas bash
presume que você esteja solicitando dotfiles. E isso inclui .
e ..
, mesmo com dotglob
. Então .git
será copiado como parte da cópia de .
.
Para contornar esse problema, você pode usar !([.]git)
(aqui [.]
torna o .
não explícito) em combinação com dotglob
ou excluir .
e ..
explicitamente com !(.git|.|..)
:
$ bash -O extglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !([.]git)'
foo .foo
$ bash -O extglob -c 'echo !(.git|.|..)'
foo .foo
No último caso, eu ainda adicionaria a opção dotglob
, porque bash
em uma versão futura pode ser corrigido para parar de incluir os dotfiles aqui como em outras shells.
Como eu uso o zsh
que tem seus próprios operadores estendidos (com a opção extendedglob
não ativada por padrão para manter a compatibilidade Bourne; ele também suporta ksh globs com a opção kshglob
, mas esses são mais complicados), faria:
set -o extendedglob # (in my ~/.zshrc)
cp -a -- ^.git(D) target/
(observe que -a
implica -r
e você precisa do --
, pois não podemos garantir que os nomes dos arquivos não começarão com -
).
^.git
é zsh
de !(.git)
do ksh. (D)
para incluir dotfiles (mas nunca .
nem ..
) apenas para esse glob.