Force Bash 4 opção 'globstar' para ignorar links simbólicos

5

O Bash 4 tem uma opção fantástica chamada 'globstar' que emula (isto é, foi roubada) a sintaxe ** do zsh para globbing em vários diretórios. No entanto, é um pouco aleijado (para meu uso, pelo menos) pelo fato de que ele sempre segue links simbólicos.

Existe uma maneira de impedir que ** siga os links simbólicos? Se não, existe algum plano para adicionar esse recurso ao Bash em uma versão futura? Até lá (ou se não houver tal plano), alguém pode sugerir uma solução decente (e conveniente)?

Acho que li que a implementação do zsh é mais flexível e não tem esse problema, mas infelizmente não posso simplesmente mudar para o zsh porque nós criamos muitos scripts bash no meu local de trabalho, e eu não ter o tempo ou o know-how para converter todos eles para zsh e mantê-los atualizados. (Eu suponho que seja possível iniciar um subshell Bash, fonte do script desejado, então de alguma forma backport todas as variáveis env alteradas, aliases, funções, etc em zsh, mas eu não sei como fazer isso, também.) / p>

Eu sei que eu poderia escrever uma função usando find que se comportaria da maneira que eu queria e então alias ** para essa função, mas eu não poderia fazer algo como path/to/parent/**/child/paths e fazer com que ela funcionasse corretamente; o mais próximo que eu poderia chegar seria algo como $(** path/to/parent child/paths) , onde ** é aliado a uma função que usa o caminho pai como primeiro argumento e inclui --wholename */child/paths/* como um argumento para o comando find que ele constrói e executa. Isso é desajeitado e feio, e eu realmente gostaria de algo melhor. (Particularmente, eu gosto que o formato path/**/path permita facilmente as variações path/** e **/path fácil e intuitivamente, enquanto uma função transformaria isso em ** path/ e ** '.' /path , respectivamente, o segundo dos quais é apenas terrível.)

Alguma opinião?

    
por Kyle Strand 18.10.2013 / 18:52

3 respostas

4

** não segue links simbólicos desde bash-4.3 .

Veja MUDANÇAS entre bash-4.3-release e bash-4.3-rc2 :

globstar (**) no longer traverses symbolic links that resolve to directories. This eliminates some duplicate entries.

    
por 04.08.2015 / 15:02
3

Não há como impedir que ** siga links simbólicos no bash, nem tenha um pedido para fornecer uma maneira encontrou qualquer resposta.

Se você sentir vontade de escrever código, poderá corrigir o bash para introduzir uma nova opção que desative o percurso simbólico com ** . Se você enviar o patch para o mantenedor do bash, isso aumentaria a chance de esse recurso estar presente um dia. No entanto, pelo menos nesse meio tempo, você acabaria tendo que implantar e manter uma versão local de um programa de sistema crítico, o que provavelmente é uma má ideia.

Não há como alterar o comportamento de ** com um alias. Se você usar uma matriz intermediária para armazenar o resultado da expansão, veja como você pode usar find :

find . … -print0 | {
  a=()
  while read -r -d "" line; do 
    a+=("$line")
  done
  frobnicate "${a[@]}"
}

Observe que a parte inteira do programa que usa a saída de find deve estar no lado direito do pipeline, pois o bash executa o lado direito de um pipeline em um subprocesso.

Se não houver problema em excluir arquivos cujo nome contenha um caractere de nova linha, será mais fácil:

set -f; IFS=
a=($(find . … ! -name $'*\n*' -print))
set +f; unset IFS
frobnicate "${a[@]}"

Você pode tentar executar seus scripts existentes no modo de emulação ksh do zsh. O Zsh não implementa todos os recursos do bash - quase toda a funcionalidade do bash existe em zsh, mas às vezes com uma sintaxe incompatível. Você também pode tentar rodar os scripts com ksh93: versões desde 93o + support ** como em zsh, e a maioria (mas não todos) dos recursos do bash são do ksh, então seus scripts podem ser facilmente portados para o ksh93. Mudar para o ksh tem o benefício adicional de que ele tende a ser mais rápido que o bash ou o zsh.

    
por 20.10.2013 / 03:49
-1

Eu descobri uma solução mais simples: use o zsh para avaliar esses globs.

Nos meus scripts de configuração do bash, tenho o seguinte:

function zeval () {
    echo $@ | zsh
}
alias z*='zeval echo'

Agora, onde quer que eu use o /path/with/**/glob no zsh, posso fazer o seguinte no bash:

$(z* sandbox/rmall_gdsarc/**/*gds)

Como os contextos nos quais os aliases são expandidos e os contextos nos quais a globbing é desejada normalmente não se sobrepõem, o alias z* nunca deve ser ambíguo.

(O único contexto em que posso pensar em que a confusão entre o alias z* e a sintaxe do Bash glob seria se você estivesse em um diretório que já estava no seu caminho contendo um script executável começando com 'z' e você queria executá-lo usando um glob ... que não faria muito sentido de qualquer maneira.)

    
por 24.01.2014 / 23:12