Porque
grep e\\.g\\. <<< "this is an e.g. wow"
e
grep e\.g\. <<< "this is an e.g. wow"
Faça a mesma coisa?
Se eu adicionar uma terceira barra, ela também terá o mesmo resultado. MAS, quando adiciono uma quarta barra, ela não funciona mais. Isso tem a ver com a pergunta de um exame antigo para uma aula. Ele perguntou se aquele com duas barras invertidas funcionaria para exibir a linha com "por exemplo". Eu originalmente pensei que não iria funcionar, mas tentei ter certeza e funcionou. Qual a explicação?
bash
shell
regular-expression
quoting
Wyatt Grant
fonte
fonte
\\\.
e daria grep,\.
mas não. boa perguntaRespostas:
Primeiro, observe que a barra única corresponde demais:
No que diz respeito ao Bash , um período de escape é o mesmo que um período. Bash passa o período para grep . Para grep, um período corresponde a qualquer coisa.
Agora, considere:
Quando o Bash vê uma barra dupla, é reduzido a uma barra única e passa para grep que, no primeiro dos três testes acima, vê, como queremos, uma barra antes de um período. Assim, isso faz a coisa certa.
Com uma barra tripla, o Bash reduz os dois primeiros a uma barra simples. Então vê
\.
. Como um período de escape não tem significado especial para o Bash, isso é reduzido para um período simples. O resultado é que o grep vê, como queremos, uma barra antes de um período.Com quatro barras, o Bash reduz cada par a uma única barra. Bash passa para grep duas barras e um ponto. O grep vê as duas barras e um ponto final e reduz as duas barras a uma única barra literal . A menos que a entrada tenha uma barra literal seguida por qualquer caractere, não há correspondências.
Para ilustrar isso, lembre-se de que, entre aspas simples, todos os caracteres são literais. Assim, dadas as três linhas de entrada a seguir, o comando grep corresponde apenas na linha com a barra literal na entrada:
Resumo do comportamento de Bash
Para o Bash, as regras são
Duas barras são reduzidas a uma única barra.
Uma barra na frente de um caractere normal, como um ponto final, é apenas o caractere normal (ponto final).
Portanto:
Existe uma maneira simples de evitar toda essa confusão: na linha de comando do Bash, expressões regulares devem ser colocadas entre aspas simples. Dentro de aspas simples, Bash deixa tudo em paz.
fonte
echo
declaração que ilustra o que o bash faz nesses casos.\.
ou.
. Para o bash, ambos são iguais: são equivalentes a um período simples. Portanto, no total, o que o bash entrega ao grep é o mesmo para os dois: uma barra simples seguida por um ponto.echo
não é uma maneira muito confiável de testar o regexp devido a muitas implementações deste programa. Por exemplo, no meu zsh (eco embutido)echo \. \\. \\\. \\\\. \\\\\.
dá. \. \. \. \.
, mas/bin/echo \. \\. \\\. \\\\. \\\\\.
retorna. \. \. \\. \\.
. Algo comoprintf "%s" ...
é provavelmente o melhor caminho.A saída é a mesma apenas para sua string, mas em geral essas expressões regulares fazem coisas diferentes. Vamos modificar um pouco o seu exemplo adicionando o segundo padrão
e,g,
(com vírgulas), o terceiroe\.g\.
(pontos), o quartoe\,g\,
(vírgulas) e a-o
opção grep para imprimir apenas as peças correspondentes.No caso seguinte
.
combinar com qualquer char (aviso''
ao redore.g.
, virei a isso mais tarde)Em seguida, escapamos
.
com barra invertida\
, portanto, apenas o literal.
será correspondido:Mas podemos escapar
\
com outro\
, para que o literal\
seja correspondido seguido por.
(ou seja, qualquer caractere):Mas se queremos corresponder apenas
\.
não,\,
então\
é necessário outro para escapar do significado especial do ponto:Agora, como você não usou o
''
argumento grep, é necessário adicionar outras barras invertidas para escapar da interpretação do shell, portanto:fonte
Quando você faz um
grep e\.g\.
, o shell está consumindo a barra invertida; portanto, você está fazendo umgrep e.g.
, que corresponde. Quando você faz umgrep e\\.g\\.
, o shell está novamente consumindo uma barra, e agora você está fazendo umgrep e\.\g.
, que novamente corresponde. Agora, parece uma barra invertida no shell\\
. Então, quando você tem\\
, o primeiro é uma sequência de escape, o segundo é uma barra invertida literal. Quando você faz agrep e\\\.g\\\.
, ela continua sendogrep e\.\g.
, porque não existe uma sequência de escape (\
) antes da primeira\
para torná-la literal\
. Lembre-se \ \ é uma barra invertida e, portanto,grep e\\\\.\\\\g
acaba sendogrep e\\.g\\.
, o que obviamente não corresponde.Para ver como o shell está vendo o que você está fazendo, use echo (por exemplo,
echo grep e\\.g\\. <<< "this is an e.g. wow"
vs.echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"
)fonte
Os dois comandos produzem a mesma saída apenas para sua entrada, mas, caso contrário, são diferentes. Para entender o que está acontecendo, precisamos saber como o parâmetro é interpretado primeiro
bash
e depois porgrep
.Escapando no bash
\
é um caractere especial que cancela o significado especial do caractere a seguir, incluindo\
ele próprio. Se o caractere a seguir não tiver significado especial, ele será passado sem alterações. Exemplos com comando e resultado:echo \a
:a
- caractere comum escapado fornece o caractereecho \\
:\
- caractere especial escapado fornece ao personagemecho \\\a
:\a
- combinação especial, comumecho \\\\
:\\
- combinação especial, especialecho
imprimirá a sequência resultante depois de abash
interpretar. Mais informações: documentação do bash , hackers festança wiki , especificação POSIX ..
não tem um significado especial embash
. É um personagem comum para o shell. Abaixo estão as sequências relevantes para seus exemplos:echo .
:.
echo \.
:.
echo \\.
:\.
echo \\\.
:\.
echo \\\\.
:\\.
Solução mais simples para cadeias literais no bash
Para passar parâmetros literalmente,
bash
você pode usar'
escape de aspas simples . Entre aspas simples, você não precisa se preocupar com o significado especial dos caracteres, porque as aspas simples são o único caractere com um significado especial. Você pode inserir uma aspas simples depois de incluir a primeira parte da sequência. Exemploecho 'part1'\''part2'
:part1'part2
Regex em grep
\
é um caractere de escape com significado semelhante ao debash
..
é um caractere especial que representa uma ocorrência única de qualquer caractere . Veja: POSIX regex , GNU grep regex . Exemplos de expressões regex:.
- corresponde a qualquer caractere comoa
ou.
\.
- corresponde apenas.
literalmenteSeus exemplos
Na segunda linha de cada exemplo abaixo, você vai encontrar equivalente com aspas simples
'
mostrando qual string literal é passado porbash
aogrep
. Depois degrep
executar, o escape do único caractere especial possível nos exemplos.
corresponde a qualquer caractere. Na terceira linha, há uma descrição com a qual a expressão corresponde.grep e.g. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
qualquer personagemg
qualquer personagem - combinae.g.
e possivelmente outras strings comoeagb
grep e\.g\. <<< "this is an e.g. wow"
grep 'e.g.' <<< "this is an e.g. wow"
e
qualquer personagemg
qualquer personagem - combinae.g.
e possivelmente outras strings comoexgy
grep e\\.g\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
literalmente - correspondee.g.
apenasgrep e\\\.g\\\. <<< "this is an e.g. wow"
grep 'e\.g\.' <<< "this is an e.g. wow"
e.g.
literalmente - correspondee.g.
apenasgrep e\\\\.g\\\\. <<< "this is an e.g. wow"
grep 'e\\.g\\.' <<< "this is an e.g. wow"
e\
qualquer caractereg\
qualquer caractere - não correspondee.g.
fonte