Quando o globstar desce em diretórios com links simbólicos?

4

Em esta postagem do Ask Ask , usei o globstar para localizar um arquivo quando PATH não está definido:

$ shopt -s globstar; for v in /**/vim; do [[ -x $v && -f $v ]] && echo "$v"; done
/etc/alternatives/vim
/usr/bin/vim
/usr/bin/X11/vim

Agora que penso nisso, essa saída parece um pouco estranha. /usr/bin/X11 é um link simbólico para /usr/bin :

$ readlink /usr/bin/X11
.

Então, há uma recursão infinita de X11 s lá, mas apenas o primeiro deles apareceu na saída. Estranhamente, apenas um /usr/** não desce para X11 :

$ printf "%s\n" /usr/bin/** | grep X11
/usr/bin/X11

Como a primeira e a última saída podem ser reconciliadas?

Dos comentários:

Estou usando a versão 4.4.18 (1) do Bash no Ubuntu 16.04.

    
por Olorin 15.12.2017 / 07:07

1 resposta

3

tl; dr - A expansão de Bash é complicada para evitar loops infinitos de links simbólicos (em bash >= 4.3 ), e você e eu interpretamos erroneamente o que ele estava fazendo nos comandos que você postou

Suponho que você tenha bash >= 4.3 , pois não consigo reproduzir o que você descreve em bash 4.2.46 , ele faz um loop até atingir um limite de recursão (conforme esperado).

Comentei isso por um tempo e configurei um diretório de teste para reproduzir o que imita a sua situação. O ponto crucial disso é como a expansão bash acontece em cada um dos seus exemplos. A expansão se comporta de maneira diferente dependendo se ela é ou não seguida por um / , e que há apenas alguma dissonância cognitiva nesse ponto para nós, primatas, ao examinar exemplos como esse.
Na documentação do bash shopt :

globstar
If set, the pattern ‘**’ used in a filename expansion context will match all files and zero or more directories and subdirectories. If the pattern is followed by a ‘/’, only directories and subdirectories match.

Para ilustrar aqui minha configuração de teste:

$ mkdir -p test/nested
$ cd test
$ touch sneaky
$ touch nested/sneaky
$ cd nested
$ ln -s . looper
$ cd ..

resultando nessa estrutura de diretório:

test/
  - sneaky
  - nested/
    - sneaky
    - looper -> ./

Isso duplica suas descobertas no meu diretório de teste:

$ for apath in ../**/sneaky; do echo "$apath"; done   
../test/nested/looper/sneaky                                                                                                                                                                 
../test/nested/sneaky
../test/sneaky

$ printf "%s\n" ../** | grep sneaky
../test/nested/sneaky
../test/sneaky

No primeiro exemplo, o glob expande para (test/nested/looper, test/nested, test) , parando em looper sem seguir o link porque o glob foi seguido por /

Em seguida, adicionamos /sneaky a isso, resultando no conjunto (test/nested/looper/sneaky, test/nested/sneaky, test/sneaky) .

No segundo exemplo, o glob expande para (test/nested/looper, test/nested/sneaky, test/nested, test/sneaky, test) (que você pode verificar removendo o | grep sneaky )

Mais uma vez, essa expansão não segue o link looper , mas, nesse caso, não acrescentamos /sneaky a ela, descartando ../test/nested/looper/sneaky de nossos resultados.

Por outro lado, continuamos a receber ../test/nested/sneaky e ../test/sneaky porque o glob também captura arquivos quando não é seguido por /

    
por 29.03.2018 / 01:37