grep interpreta mal o padrão da variável

2

Eu tenho um problema com padrão de escape colocado em grep .

Meu arquivo de teste é:

export_cc = ${dir}/aaa/bbb/ccc
export_cc = ${dir}/aaa/bbb/eee
export_cc = ${dir}/aaa/bbb/ddd
export_cc = ${dir}/aaa/bbb/fff
export_cc = ${dir}/aaa/bbb/ggg

Se eu correr:

~/programming/sandbox $ printf %q 'export_cc = ${dir}/aaa/bbb/ccc'
export_cc\ =\ \$\{dir\}/aaa/bbb/ccc

e depois copiar a saída para o grep como o padrão que eu obteria:

~/programming/sandbox $ grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
export_cc = ${dir}/aaa/bbb/ccc

Mas se eu colocar o padrão na variável ou nos backticks eu obteria:

~/programming/sandbox $ grep 'printf %q 'export_cc = ${dir}/aaa/bbb/ccc'' file
grep: Trailing backslash 

Alguém poderia me dizer por que isso faz a diferença e como usar uma string entre aspas na variável como um padrão grep ?

    
por user2551229 01.06.2015 / 19:09

1 resposta

3

O problema era escape de shell . \ é um caractere especial no shell e também em grep .

Em:

grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file

export_cc\ =\ \$\{dir\}/aaa/bbb/ccc foi interpretado pelo shell para uma string export_cc = ${dir}/aaa/bbb/ccc antes de passar para grep . Você pode usar o strace para verificar:

$ strace grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
execve("/bin/grep", ["grep", "export_cc = ${dir}/aaa/bbb/ccc",...

Com Substituição de comando :

grep 'printf %q 'export_cc = ${dir}/aaa/bbb/ccc'' file

Sem as aspas duplas, o resultado da substituição de comandos foi split e glob por o shell em três partes: export_cc\ , =\ e \$\{dir\}/aaa/bbb/ccc . O shell tratou-os como três strings, escapando de todas as barras invertidas e passando-os para grep como export_cc\ , =\ , \$\{dir\}/aaa/bbb/ccc :

$ strace grep $(printf %q 'export_cc = ${dir}/aaa/bbb/ccc') file
execve("/bin/grep", ["grep", "export_cc\", "=\", "\$\{dir\}/aaa/bbb/ccc",...

grep recebeu um padrão com uma barra invertida export_cc\ seguido por nada e mostrou a mensagem Trailing backslash .

Para que funcione, você precisa substituir o comando por aspas duplas e usar printf com %s em vez de %q :

$ grep "$(printf %s 'export_cc = ${dir}/aaa/bbb/ccc')" file
export_cc = ${dir}/aaa/bbb/ccc
    
por 01.06.2015 / 19:38