En la mayoría de los shells nullglob
no es el predeterminado. Eso significa, por ejemplo, que si ejecuta este comando
ls *
en un directorio vacío, expandirá el *
glob a un *
literal , en lugar de una lista vacía de argumentos. Hay formas de cambiar ese comportamiento, de modo que *
en un directorio vacío devolverá una lista vacía de argumentos, lo que parecería más intuitivo.
Entonces, ¿hay alguna razón por la que nullglob
está deshabilitado por defecto? Si es así, ¿cuál es ese motivo?
Respuesta aceptada:
El nullglob
opción (que por cierto es un zsh
invención, solo se agregó 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 ejecutaría ls
sin argumento que se trata como ls -- .
(enumere el directorio actual) si ningún archivo coincide, lo que probablemente sea peor que llamar a 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
en stdin 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 un failglob
opción para eso (interesante para esta discusión, ya que contrario a 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 de finalización de bash).
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
Puedes obtener ese comportamiento con zsh
con setopt cshnullglob
aunque una forma más sensata de hacerlo en zsh
sería usar un glob como:
ls -- *.(txt|html)
En zsh
y ksh93
, también puede aplicar nullglob por 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 txt
archivo en lugar de fallar el comando con un error (o convertirlo en una matriz con un *.txt
argumento literal con otros shells).
Versiones de fish
antes de 2.3 funcionaría como bash -O nullglob
pero da una advertencia cuando es interactivo cuando un globo no tiene coincidencia. Desde 2.3, funciona como zsh
a excepción de los globos usados en for
, set
o count
.
Ahora, en la nota de historial, el comportamiento en realidad estaba roto por la concha de Bourne. En versiones anteriores de Unix, el globbing se realizaba a través de /etc/glob
ayudante y ese ayudante se comportó como csh
:fallaría el comando si ninguno de los globos coincidiera con ningún archivo y, de lo contrario, eliminaría los globos sin coincidencia.
Así que la situación en la que nos encontramos hoy se debe a una mala decisión tomada en el caparazón de Bourne.
Tenga en cuenta que el shell Bourne (y el shell C) vienen con otra característica nueva de Unix:el entorno. Eso significaba una expansión variable (su predecesor solo tenía el $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 globbing (y división) en la expansión de variables y sustitución de comandos (posiblemente por compatibilidad con versiones anteriores del shell Thompson donde echo $1
todavía invocaría /etc/glob
si $1
contenía comodines (era más como una expansión de macro de preprocesador allí, ya que el valor expandido se analizó nuevamente como código de shell)).
Los globos que fallan y no coinciden significarían, por ejemplo, que:
pattern='a.*b'
grep $pattern file
fallaría el comando (a menos que haya algún a.whateverb
archivos en el directorio actual). csh
(que también realiza globbing sobre la expansión variable) falla el comando en ese caso (y diría que es mejor que dejar un error inactivo allí, incluso si no es tan bueno como no hacer globbing como en zsh
).