Zsh está tratando uma string como um padrão de nome de arquivo e reclamando disso (opção NOMATCH)

Zsh está tratando uma string como um padrão de nome de arquivo e reclamando disso (opção NOMATCH)

Estou testando o Zsh, vindo do Bash. Eu estava tendo dificuldade para entender por que o Zsh reclama de um grep regex.

usr@rk1 ~ % tty | grep ^/dev/tty[1-7]$ > /dev/null 2>&1
zsh: no matches found: ^/dev/tty[1-7]$

Percebi que a saída desaparece e tudo fica bem se (1) eu colocar o regex entre aspas, (2) remover as barras do regex ou (3) usar setopt NO_NOMATCH.

Do manual zshoptions:

NOMATCH (+3) <C> <Z>

Se um padrão para geração de nome de arquivo não tiver correspondências, imprima um erro, em vez de deixá-lo inalterado na lista de argumentos. Isso também se aplica à expansão de arquivo de um '~' ou '=' inicial.

Então, parece-me que o regex está sendo tratado como um padrão de nome de arquivo por causa das barras. Isso é considerado normal ou um bug?

Além disso, seria ótimo ter algo semelhante às páginas Bashism e BashPitfalls do GreyCat, mas para Zsh. Você conhece esse recurso?

Responder1

Se você definiu a EXTENDED_GLOBopção, o padrão ^somethingserá usado para geração de nome de arquivo. Dezshexpnpágina de manual:

^x (Requer que EXTENDED_GLOB seja definido.) Corresponde a qualquer coisa, exceto ao padrão x. Isso tem uma precedência maior que /, portanto, ^foo/bara pesquisa será feita em diretórios, .exceto ./foopor um arquivo chamado bar.

Então, ^/dev/tty[1-7]$está tentando encontrar em cada subdiretório (nada é excluído, porque ^é seguido diretamente por /) do diretório atual para um arquivo chamado dev/tty1$, dev/tty2$, ..., dev/tty7$que [1-7]corresponda exatamente a um caractere no intervalo entre 1 e 7. $é ' Não foi tratado de forma especial nesse caso.

Você já encontrou a solução, defina NO_NOMATCH(pode ser perigoso, mas gosto muito porque tenho preguiça de digitar ;)) ou coloque aspas (aspas simples ou duplas) o acento circunflexo.

Tente com printo que está acontecendo:

$ 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]$

Sem EXTENDED_GLOBset, o cursor é interpretado literalmente como um caractere normal. Portanto, citar é seu amigo novamente - desta vez apenas [1-7]aciona a geração do nome do arquivo:

$ 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$

Então, resumindo: citar o padrão regex parece sempre uma boa ideia para mim - embora eu normalmente também tente salvar algumas teclas digitadas.

informação relacionada