evento bash não encontrado tentando corresponder e excluir parênteses no grep

1

Em uma linha muito longa, vou resumir com:

(foo),(bar,baz(word,right),(end)

Eu quero imprimir apenas:

      (bar,baz(word,right

Para corresponder ao segundo parêntese, excluir a palavra que segue a terceira:

$ grep -oP "\(.*(?!word).*right"

mas o Bash interpreta o ponto de exclamação:

-bash: !word: event not found

Proteger o ponto de exclamação com orçamento simples falha com grep: missing )

$ grep -oP '\(.*(?!word).*right'
$ grep -oP '\((?!word)(.*right)'

Proteger o ponto de exclamação com barra invertida falha com grep: unrecognized character after (? or (?-

Alguma ideia?

Nota: -P é para o regex Perl e -o é para imprimir apenas a parte correspondente de uma linha

    
por Philippe Blayo 31.03.2014 / 15:52

5 respostas

4

As regras são diferentes para aspas simples versus aspas duplas.

Pelo motivo que você mostra, aspas duplas não podem ser usadas de forma confiável no bash, porque não há uma maneira sã de escapar de um ponto de exclamação.

$ grep -oP "\(.*(?!word).*right"
bash: !word: event not found

$ grep -oP "\(.*(?\!word).*right"
grep: unrecognized character after (? or (?-

A segunda é porque o bash passa por \! em vez de ! para grep. Mostrando isto:

$ printf '%s' "\!"
\!

Quando você tentou aspas simples, a barra invertida dupla não significa uma barra invertida de escape, isso significa duas barras invertidas.

$ printf '%s' '\(.*(?!word).*right'
\(.*(?!word).*right

Dentro de aspas simples, tudo é literal e não há escapes, então a maneira de escrever a expressão regular que você está tentando é:

$ grep -oP '\(.*(?!word).*right'
    
por 31.03.2014 / 17:09
3

Se você deseja combinar do segundo parêntese aberto até (mas não incluindo) os próximos parênteses de fechamento:

grep -Po '\(.*?\K\([^)]*'

Ou portável com sed :

sed -n 's/^[^(]*([^(]*\(([^)]*\).*//p'

Para corresponder à direita mais ( que não é seguido por word até o mais à direita right depois disso:

grep -Po '.*\K\((?!word).*right'
    
por 31.03.2014 / 16:19
2

Você pode fazer isso com awk :

$ echo '(foo),(bar,baz(word,right),(end)' | awk -F'),' '{print $2}'
(bar,baz(word,right
    
por 31.03.2014 / 15:57
0

Procure a vírgula parens antes e depois:

grep -oP '(?<=,)\(.*(?=\),)'

Exemplo

$ echo '(foo),(bar,baz(word,right),(end)' | grep -oP '(?<=,)\(.*(?=\),)'
(bar,baz(word,right

O lookahead e o behind só podem procurar por strings explícitas, não é possível encontrar coisas como .* .

Referências

por 31.03.2014 / 16:05
0

Se por algum motivo você não puder usar aspas simples como sugerido na resposta de Mikel, você pode desativar temporariamente a expansão do histórico usando set +H (ligue-o novamente com set -H ), como sugerido por glenn jackman nos comentários. p>     

por 02.10.2014 / 11:39