Na maioria das conchas nullglob
não é o padrão. Isso significa, por exemplo, se você executar este comando
ls *
em um diretório vazio, ele expandirá o *
glob para um literal *
, em vez de uma lista vazia de argumentos. Existem maneiras de mudar esse comportamento, para que *
em um diretório vazio retorne uma lista vazia de argumentos, o que pareceria mais intuitivo.
Portanto, existe um motivo para nullglob
estar desativado por padrão? Se sim, qual é esse motivo?
*
é um glob e se expande para todos os arquivos existentes ; como é "intuitivo" haver um caso especial em que os globs de diretório vazios são "expandidos" para um literal*
?Respostas:
A
nullglob
opção (que BTW é umazsh
invenção, adicionada apenas anos depois abash
(2.0
)) não seria ideal em vários casos. Els
é um bom exemplo:Ou seu equivalente mais correto:
Com
nullglob
on seria executadols
sem argumento que é tratado comols -- .
(liste o diretório atual) se nenhum arquivo corresponder, o que provavelmente é pior do que chamarls
com um literal*.txt
como argumento.Você teria problemas semelhantes com a maioria dos utilitários de texto:
Procuraria
foo
no stdin se não houvertxt
arquivo.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 umafailglob
opção para isso (interessante para esta discussão, pois ao contrário daash
AT&Tksh
ouzsh
,bash
nã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:fish
bash -O failglob
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á:
Você pode obter esse comportamento com
zsh
comsetopt cshnullglob
embora uma forma mais sensata de fazê-lo emzsh
seria a utilização de um glob como:No
zsh
eksh93
, você também pode aplicar o nullglob por glob, o que é uma abordagem muito mais saudável do que modificar uma configuração global:criaria uma matriz vazia se não houver
txt
arquivo em vez de falhar no comando com um erro (ou torná-la uma matriz com um*.txt
argumento literal com outras conchas).As versões
fish
anteriores à 2.3 funcionariam comobash -O nullglob
um aviso quando interativas quando uma glob não tem correspondência. Desde a versão 2.3, funciona como,zsh
exceto os globs usados emfor
,set
oucount
.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/glob
auxiliar e ele se comportava da seguinte maneiracsh
: 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 $1
ainda invocaria/etc/glob
se houvesse$1
curingas (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:
falharia no comando (a menos que haja alguns
a.whateverb
arquivos 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 emzsh
).fonte
nullglob
parece interromper o preenchimento da guia (pressionar a tecla tab não faz nada quando está ativado).files=$(shopt -s nullglob;echo *.txt)
xpg_echo
) em variáveis escalares . Você precisa de algo comoreadarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)
combash
4.4 ou acima ou(shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmd
com GNUxargs
para que isso seja útil a todos com nomes de arquivos arbitrários. Ou, ainda com o bash4.4, use uma função auxiliar que uselocal -
(copiada do ash 25 anos depois) para um escopo local de opções.