Estoy probando Zsh, procedente de Bash. Me estaba costando un poco entender por qué Zsh se queja de una expresión regular grep.
usr@rk1 ~ % tty | grep ^/dev/tty[1-7]$ > /dev/null 2>&1
zsh: no matches found: ^/dev/tty[1-7]$
Noté que el resultado desaparece y todo está bien si (1) envuelvo la expresión regular entre comillas, (2) elimino las barras de la expresión regular o (3) uso setopt NO_NOMATCH
.
Del manual de zshoptions:
NO COINCIDENCIA (+3) <C> <Z>
Si un patrón para la generación de nombres de archivos no coincide, imprima un error, en lugar de dejarlo sin cambios en la lista de argumentos. Esto también se aplica a la expansión del archivo con un '~' o '=" inicial.
Entonces, me parece que la expresión regular se trata como un patrón de nombre de archivo debido a las barras. ¿Se considera esto normal o un error?
Además, sería genial tener algo similar a las páginas Bashism y BashPitfalls de GreyCat pero para Zsh. ¿Conoce dicho recurso?
Respuesta1
Si ha configurado la EXTENDED_GLOB
opción, el patrón ^something
se utiliza para la generación de nombres de archivos. Desde elzshexpnpágina de manual:
^x
(Requiere que se establezca EXTENDED_GLOB). Coincide con cualquier cosa excepto con el patrón x. Esto tiene una prioridad mayor que/
, por lo que^foo/bar
buscará en directorios.
excepto en./foo
un archivo llamadobar
.
Por lo tanto, ^/dev/tty[1-7]$
está intentando buscar en cada subdirectorio (no se excluye nada, porque ^
va seguido directamente de /
) del directorio actual un archivo llamado dev/tty1$
,, dev/tty2$
..., dev/tty7$
que [1-7]
coincida exactamente con un carácter en el rango entre 1 y 7 $
. No se trata de manera especial en ese caso.
Ya encontraste la solución, establece NO_NOMATCH
(puede ser peligroso, pero me gusta mucho porque soy flojo escribiendo ;)
) o comillas (comillas simples o dobles) el signo de intercalación.
Prueba con print
lo que está pasando:
$ setopt nomatch extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$
# ^ is doing filename generation in every sub-dir
$ touch foo/dev/tty5$
$ echo ^/dev/tty[1-7]$
foo/dev/tty5$
# quote to prevent filename generation
$ echo "^/dev/tty[1-7]$"
^/dev/tty[1-7]$
$ echo '^/dev/tty[1-7]$'
^/dev/tty[1-7]$
Sin EXTENDED_GLOB
conjunto, el símbolo de intercalación se interpreta literalmente como un carácter normal. Entonces, citar es tu amigo nuevamente; esta vez solo [1-7]
desencadena la generación del nombre de archivo:
$ setopt nomatch no_extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$
# quote to prevent filename generation
$ echo ^/dev/tty"[1-7]"$
^/dev/tty[1-7]$
# caret is interpreted literally
$ mkdir ^/dev -p
$ touch ^/dev/tty5$
$ echo ^/dev/tty[1-7]$
^/dev/tty5$
Entonces, resumiendo: citar el patrón de expresiones regulares siempre me parece una buena idea, aunque normalmente también intento ahorrar algunas pulsaciones de teclas.