Por que não pode encontrar -regex corresponde a uma nova linha?

5

Por que isso falha?

touch "$(printf "a\nb")"; find . -regex './.\n.'

Eu também tentei estes, nenhum dos quais funciona:

find . -regextype posix-extended -regex '.\n.'
find . -regextype posix-awk -regex '.\n.'
find . -regextype posix-basic -regex '.\n.'
find . -regextype posix-egrep -regex '.\n.'

A única maneira que parece funcionar é (obrigado @MichaelMrozek)

find . -regex './.'$'\n''.'

O que é complicado para dizer o mínimo. Então, por que as expressões regulares do find parecem não conseguir lidar com \n ?

Atualizar em resposta a respostas até agora:

OK, entendo que \n não faz parte do ERE e que foi um dos meus mal-entendidos, mas find alega posix-awk e gawk e mawk correspondem \n como esperado:

$ printf "f1l1\nhas newline:f2l1#f1l2 does not:f2l2#" | 
    mawk -F: 'BEGIN{RS="#"}; ($1~/\n/){print $1}' 
f1l1
has newline

Eu não tenho um awk puro para testar com talvez POSIX awk não coincide? Caso contrário, find não está realmente implementando posix-awk expressões regulares?

    
por terdon 10.03.2014 / 17:54

3 respostas

12

Porque o GNU find não suporta \n como uma seqüência de escape. O regexp \n corresponde ao caractere n . O GNU encontra cópias da sintaxe tradicional do Emacs, que também não possui esse recurso.

Enquanto o GNU find suporta outras sintaxes de regex, nenhum suporta backslash-letter ou backslash-octal para indicar caracteres de controle. Você precisa incluir o caractere de controle literalmente no argumento.

Existem muitas sintaxes de regex diferentes. Nem POSIX expressões regulares básicas (BRE) nem expressões regulares expandidas (ERE) incluem escapes \n ou backslash-octal. Ambas as definições deixam o significado de contrabarra quando não seguidas por um caractere especial indefinido. Os utilitários awk e sed ambos suportam \n para significar uma nova linha; isso é específico para esses utilitários (e comuns, mas, como você vê, não são universais).

De um script de shell, você pode escrever

find . -regex $'./.\n.'     # ksh/bash/zsh only
find . -regex './.
.'
find . -name '*
*'

¹ Logicamente: para uso interativo, você pode digitar qualquer caractere com C-q ; para uso de programação, \n existe como parte da sintaxe literal da string.

    
por 10.03.2014 / 18:22
5

Não é possível corresponder uma nova linha com '\ n' porque não tem um significado especial em uma expressão regular (linha de quebra, por exemplo), mas você pode corresponder ao fim da linha com a expressão regular $ .

    
por 10.03.2014 / 18:12
1

Acho que find usando a função fnmatch na biblioteca C padrão, portanto, se FNM_NOESCAPE não estiver definido, um caractere de barra invertida no padrão seguido por qualquer outro caractere corresponderá a esse segundo caractere em string.

FNM_NOESCAPE

Don't treat the '\' character specially in patterns. Normally, '\' quotes
the following character, turning off its special meaning (if any) so that it 
matches only itself. When quoting is enabled, the pattern '\?' matches only 
the string '?', because the question mark in the pattern acts like an 
ordinary character. If you use FNM_NOESCAPE, then '\' is an ordinary character.

Eu verifico com find (GNU findutils) 4.4.2 e glibc 2.15 , esta opção está desativada. verifique line 42 em fnmatch.h :

#define FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
    
por 10.03.2014 / 18:57