A opção nullglob (que BTW é uma invenção zsh , adicionada anos depois a bash ( 2.0 )) não seria ideal em vários casos. E ls é um bom exemplo:
ls *.txt
Ou o seu equivalente mais correto:
ls -- *.txt
Com nullglob on, executar ls sem nenhum argumento tratado como ls -- . (listar o diretório atual) se nenhum arquivo corresponder, o que provavelmente é pior do que chamar ls com um literal *.txt como argumento.
Você teria problemas semelhantes com a maioria dos utilitários de texto:
grep foo *.txt
Procuraria foo no stdin se não houver arquivo txt .
Um padrão mais sensato, e o de csh, tcsh, zsh ou fish 2.3+ (e de shells iniciais do Unix) é cancelar o comando se o glob não corresponder.
bash (desde a versão 3) tem uma opção failglob para isso (interessante para esta discussão, pois ao contrário de ash , AT & T ksh ou zsh , bash não suporta Escopos locais para opções (embora isso mude em 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 de zsh , fish ou bash -O failglob em casos como:
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 torna:
ls -- file.txt
Você pode obter esse comportamento com zsh com setopt cshnullglob , embora uma maneira mais sensata de fazer isso em zsh seria usar um glob como:
ls -- *.(txt|html)
Em zsh , você também pode aplicar nullglob em uma base por glob, que é uma abordagem muito melhor do que modificar uma configuração global:
files=(*.txt(N))
criaria uma matriz vazia se não houver nenhum arquivo txt em vez de falhar o comando com um erro (ou torná-lo uma matriz com um argumento *.txt literal com outros shells).
As versões de fish anteriores a 2.3 funcionariam como bash -O nullglob , mas emitiriam um aviso quando interativas quando uma glob não tivesse correspondência. Desde o 2.3, ele funciona como zsh , exceto para globs usados em for , set ou count .
Agora, na nota de histórico, o comportamento foi realmente quebrado pela shell Bourne. Nas versões anteriores do Unix, o globbing era feito através do /etc/glob helper e esse ajudante se comportava como csh : ele falharia o comando se nenhum dos globs correspondesse a nenhum arquivo e removeria os globs sem nenhuma correspondência.
Então, a situação em que estamos hoje é devido a uma má decisão tomada no shell Bourne.
Observe que o shell Bourne (e o shell C) veio com outro novo recurso Unix: o ambiente. Isso significava expansão variável (seu antecessor tinha apenas os parâmetros $1 , $2 ... posicionais). O shell Bourne também introduziu a substituição de comandos.
Outra falha na decisão de design do shell Bourne era realizar globbing (e divisão) na expansão de variáveis e na substituição de comando (possivelmente para compatibilidade com o shell Thompson, em que echo $1 ainda invocaria /etc/glob if $1 continham curingas (era mais parecido com uma expansão de macro pré-processador, como no valor expandido foi analisado novamente como código de shell)).
Globs com falha que não correspondem significaria, por exemplo, que:
pattern='a.*b'
grep $pattern file
falharia o comando (a menos que haja alguns arquivos a.whateverb no diretório atual). csh (que também executa globbing na expansão de variáveis) falha o comando nesse caso (e eu diria que é melhor do que deixar um erro inativo lá, mesmo que não seja tão bom quanto não fazer globbing como em zsh ).