A nullglobopção (que BTW é uma zshinvenção, adicionada apenas anos depois a bash( 2.0)) não seria ideal em vários casos. E lsé um bom exemplo:
ls *.txt
Ou seu equivalente mais correto:
ls -- *.txt
Com nullglobon seria executado lssem argumento que é tratado como ls -- .(liste o diretório atual) se nenhum arquivo corresponder, o que provavelmente é pior do que chamar lscom um literal *.txtcomo argumento.
Você teria problemas semelhantes com a maioria dos utilitários de texto:
grep foo *.txt
Procuraria foono stdin se não houver txtarquivo.
Um padrão mais sensato, e o de csh, tcsh, zsh ou fish 2.3+ (e dos shells iniciais do Unix) é cancelar o comando completamente se o glob não corresponder.
bash(desde a versão 3) tem uma failglobopção para isso (interessante para esta discussão, pois ao contrário da ashAT&T kshou zsh, bashnão suporta escopos locais para opções (embora isso mude no 4.4), essa opção, quando ativada globalmente, quebra algumas coisas como as funções de conclusão do bash).
Observe que csh e tcsh são um pouco diferentes ou zsh, em casos como:fishbash -O failglob
ls -- *.txt *.html
Onde você precisa que todos os globs não correspondam para que o comando seja cancelado. Por exemplo, se houver um arquivo txt e nenhum arquivo html, isso se tornará:
ls -- file.txt
Você pode obter esse comportamento com zshcom setopt cshnullglobembora uma forma mais sensata de fazê-lo em zshseria a utilização de um glob como:
ls -- *.(txt|html)
No zshe ksh93, você também pode aplicar o nullglob por glob, o que é uma abordagem muito mais saudável do que modificar uma configuração global:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
criaria uma matriz vazia se não houver txtarquivo em vez de falhar no comando com um erro (ou torná-la uma matriz com um *.txtargumento literal com outras conchas).
As versões fishanteriores à 2.3 funcionariam como bash -O nullglobum aviso quando interativas quando uma glob não tem correspondência. Desde a versão 2.3, funciona como, zshexceto os globs usados em for, setou count.
Agora, na nota da história, o comportamento foi realmente quebrado pelo shell Bourne. Nas versões anteriores do Unix, o globbing era feito através do /etc/globauxiliar e ele se comportava da seguinte maneira csh: falharia no comando se nenhum dos globs correspondesse a qualquer arquivo e os removesse sem nenhuma correspondência.
Portanto, a situação em que estamos hoje se deve a uma má decisão tomada no shell Bourne.
Observe que o shell Bourne (e o shell C) veio com outro novo recurso do Unix: o ambiente. Essa expansão variável significava (é predecessor só tinha os $1, $2... parâmetros posicionais). O shell Bourne também introduziu a substituição de comandos.
Outra má decisão de design do shell Bourne foi realizar globbing (e divisão) após a expansão de variáveis e substituição de comandos (possivelmente para compatibilidade com versões anteriores com o shell Thompson, onde echo $1ainda invocaria /etc/globse houvesse $1curingas (era mais como expansão macro de pré-processador) lá, como no valor expandido, foi analisado novamente como código shell)).
Globs com falha que não correspondem significam, por exemplo, que:
pattern='a.*b'
grep $pattern file
falharia no comando (a menos que haja alguns a.whateverbarquivos no diretório atual). csh(que também executa globbing na expansão de variáveis) falha no comando nesse caso (e eu diria que é melhor do que deixar um bug inativo lá, mesmo que não seja tão bom quanto não fazer globbing como em zsh).