Zsh trata una cadena como un patrón de nombre de archivo y se queja de ello (opción NOMATCH)

Zsh trata una cadena como un patrón de nombre de archivo y se queja de ello (opción NOMATCH)

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_GLOBopción, el patrón ^somethingse 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/barbuscará en directorios .excepto en ./fooun archivo llamado bar.

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 printlo 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_GLOBconjunto, 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.

información relacionada