Comportamento diferente de sed em relação a um array e uma string na presença de barras invertidas

1

Deixe o arquivo foo.txt conter

foo\ bar baz 
xx

Por que o seguinte altera corretamente "foo \\ bar" para "someotherstuff" em foo.txt ?

sed -i 's/foo\\ bar/someotherstuff/gI' foo.txt

enquanto isso não acontece?

a=("foo\\ bar") 
b=(someotherstuff) 

for ((i=0;i<${#a[@]};++i)); do 
    sed -i "s/${a[i]}/${b[i]}/gI" foo.txt 
done

Eles devem ser o mesmo.

    
por Faheem Mitha 07.02.2014 / 19:55

2 respostas

3

man bash explica os perigos do uso de aspas duplas:

   Enclosing  characters  in  double  quotes pre‐
   serves the literal  value  of  all  characters
   within the quotes, with the exception of $, ',
   \, and, when history expansion is enabled,  !.
   The  characters  $  and ' retain their special
   meaning within double quotes.   The  backslash
   retains its special meaning only when followed
   by one of the following characters: $,  ',  ",
   \, or <newline>.  A double quote may be quoted
   within double quotes by preceding  it  with  a
   backslash.  If enabled, history expansion will
   be performed unless an !  appearing in  double
   quotes  is  escaped  using  a  backslash.  The
   backslash preceding the !  is not removed.

Em outras palavras, use aspas duplas em torno de uma variável bash quando desejar que o bash processe sinais de dólar, backquotes, barras invertidas e pontos de exclamação.

Quando você quiser que uma string seja sed passada ao sed, use aspas simples, como no seu primeiro exemplo. man bash explica:

   Enclosing  characters  in  single  quotes pre‐
   serves the literal  value  of  each  character
   within  the  quotes.   A  single quote may not
   occur between single quotes,  even  when  pre‐
   ceded by a backslash.

Em suma, existem duas alternativas. Um usa aspas simples ao definir a :

$ a=('foo\\ bar')
$ b=(someotherstuff)
$ sed  "s/${a[0]}/${b[0]}/gI" foo.txt
someotherstuff baz 
xxx

e o segundo usa aspas duplas ao definir a :

$ a=("foo\\\\ bar")
$ sed  "s/${a[0]}/${b[0]}/gI" foo.txt
someotherstuff baz 
xxx

O último requer oito barras invertidas. Porque você quer substituir duas barras invertidas, você tem que fornecer sed com quatro barras invertidas. Para fornecer sed com quatro, você tem que fornecer bash, ao usar aspas duplas, com oito.

    
por 07.02.2014 / 20:00
1
a=("foo\\ bar") 

produz como um valor para ${a[0]} :

"foo\ bar"

que é o que está sendo enviado para sed , que então procura por:

"foo\ bar"

que não corresponde a nenhuma linha em sua entrada.

    
por 07.02.2014 / 19:58