La nullglob
opción (que por cierto es una zsh
invención, solo añadida años después a bash
( 2.0
)) no sería ideal en varios casos. Y ls
es un buen ejemplo:
ls *.txt
O su equivalente más correcto:
ls -- *.txt
Con nullglob
on se ejecutaría ls
sin ningún argumento que se trata como ls -- .
(enumere el directorio actual) si no coinciden los archivos, lo que probablemente sea peor que llamar ls
con un literal *.txt
como argumento.
Tendría problemas similares con la mayoría de las utilidades de texto:
grep foo *.txt
Buscaría foo
la entrada estándar si no hay txt
archivo.
Un valor predeterminado más sensato, y el de csh, tcsh, zsh o fish 2.3+ (y de los primeros shells de Unix) es cancelar el comando por completo si el glob no coincide.
bash
(desde la versión 3) tiene una failglob
opción para eso (interesante para esta discusión, ya que al contrario de ash
AT&T ksh
o zsh
, bash
no admite ámbitos locales para las opciones (aunque eso cambiará en 4.4), esa opción cuando está habilitada globalmente rompe algunas cosas como las funciones bash-complete).
Tenga en cuenta que csh y tcsh son ligeramente diferentes de zsh
, fish
o bash -O failglob
en casos como:
ls -- *.txt *.html
Donde necesita que todos los globos no coincidan para que se cancele el comando. Por ejemplo, si hay un archivo txt y ningún archivo html, se convierte en:
ls -- file.txt
Usted puede conseguir que el comportamiento con zsh
la setopt cshnullglob
aunque de una manera más sensata de hacerlo en zsh
sería utilizar un pegote como:
ls -- *.(txt|html)
En zsh
y ksh93
, también puede aplicar nullglob en función de cada globo, que es un enfoque mucho más sensato que modificar una configuración global:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
crearía una matriz vacía si no hay un txt
archivo en lugar de fallar el comando con un error (o convertirlo en una matriz con un *.txt
argumento literal con otros shells).
Las versiones fish
anteriores a la 2.3 funcionarían de la misma manera bash -O nullglob
pero darían una advertencia cuando sean interactivas cuando un globo no tenga coincidencia. Desde 2.3, funciona como zsh
excepto para los globos utilizados en for
, set
o count
.
Ahora, en la nota del historial, el comportamiento fue realmente roto por el shell Bourne. En versiones anteriores de Unix, el bloqueo se realizaba a través del /etc/glob
ayudante y ese ayudante se comportaba como csh
: fallaría el comando si ninguno de los globos coincidía con ningún archivo y, de lo contrario, eliminaría los globos sin coincidencia.
Entonces, la situación en la que estamos hoy se debe a una mala decisión tomada en el shell Bourne.
Tenga en cuenta que el shell Bourne (y el shell C) vienen con otra nueva característica de Unix: el entorno. Eso significa la expansión de variables (su predecesor sólo tenía los $1
, $2
... parámetros posicionales). El shell Bourne también introdujo la sustitución de comandos.
Otra mala decisión de diseño del shell Bourne fue realizar el bloqueo (y la división) tras la expansión de las variables y la sustitución de comandos (posiblemente por compatibilidad con el shell Thompson, donde echo $1
aún se invocaría /etc/glob
si $1
contuviera comodines (era más como una expansión de macro preprocesador). allí, como en el valor expandido, se analizó nuevamente como código shell)).
Los globos fallidos que no coinciden significarían, por ejemplo, que:
pattern='a.*b'
grep $pattern file
fallaría el comando (a menos que haya algunos a.whateverb
archivos en el directorio actual). csh
(que también realiza el bloqueo en la expansión variable) falla el comando en ese caso (y diría que es mejor que dejar un error latente allí, incluso si no es tan bueno como no hacerlo en absoluto zsh
).