Substituir string em um arquivo por outro, onde ambos são salvos em variáveis

4

Eu quero substituir uma string encontrada em um arquivo por outra, mas ambos têm um caractere especial (neste exemplo, é um . char), por exemplo, 1.0 e 2.0 .

Então este é o comando usado atualmente:

sed -i 's/1\.0/2\.0/g' /home/user1/file1.txt

E se 1.0 e 2.0 fossem salvos nas variáveis $i e $j ? onde i tem o valor 1.0 e j tem o valor 2.0 , como posso ainda substituir i por j ?

    
por Tak 12.03.2015 / 04:08

2 respostas

1

Você pode usar apenas sed para fazer a correção para você:

printf '%s\n' "$i" "$j" |
sed 's/[]\$*&/.^[]/\&/g;H;$!d
     x;y|\n|/|;s|.*|s&/g|' |
sed -f - /path/to/infile

Portanto, este s/// ubstitution irá escapar de todos / quaisquer metacaracteres do BRE na entrada:

s/[]\$*&/.^[]/\&/g

... prefixando cada um com uma barra invertida. O primeiro sed , em seguida, salva uma cópia da primeira linha - $i - em H old space, adicionando um caractere \n ewline a ele. A linha $i é então d eletida porque é ! não a $ anterior. A próxima linha - a $j line - também é a última, e depois de receber o mesmo tratamento da primeira, ela não é d eleted. Em vez disso, ele e x altera os buffers de retenção e padrão e opera nos resultados concatenados. Neste ponto, o espaço padrão é semelhante:

\n1\.0\n2\.0

... por isso, y/// traduz todos os \n ewlines para / slashes, s/// ubstitute .* todo o espaço padrão para & em si, mais um s pré-anexado e um% anexado/g que nos leva:

s/1\.0/2\.0/g

Isso é automaticamente impresso para o segundo sed que está lendo stdin - ou -f - - como seu script. Quando o primeiro sed for concluído e fechar o pipe entre eles, o segundo sed começará a aplicar ...

s/1\.0/2\.0/g

... para cada linha em seu arquivo de entrada nomeado - que está aqui /path/to/infile .

Eu escrevi seu arquivo assim:

printf '%04s%04s%04s%04s\n' \
        0 0 -1 0 1 0 0 0 0 -1\
        0 0 1.5 2.0 1.0 0 >/tmp/temp

O que me deu um arquivo como ...

   0   0  -1   0
   1   0   0   0
   0  -1   0   0
 1.5 2.0 1.0   0

Eu então escrevi uma versão diferente do seu script como:

ii=0.0
for i in        1.0 2.0 3.0 4.0
do      str2=$i
        printf '3[41m## %s 3[0m\n' \
                "str2 = $str2" "$ii $str2"
        printf %s\n "$ii" "$str2"
        ii=$str2
done | 
sed '   s/[]\$^&*./[]/\&/g;H;x
        s|^\(\n\)\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)|\
        bs:ii\\:ss///gp;ti|p
        s|||;h;d' |
sed -f - /tmp/temp

O qual usa o shell apenas para gerar as strings, mas permite que sed faça todo o processamento de dados. Observe que, embora dois sed s sejam chamados, cada um deles é chamado apenas uma vez.

Quando eu executo, os resultados são:

   0   0  -1   0
   1   0   0   0
   0  -1   0   0
 1.5 2.0 2.0   0
## str2 = 2.0 
## 1.0 2.0 
 1.5 3.0 3.0   0
## str2 = 3.0 
## 2.0 3.0 
 1.5 4.0 4.0   0
## str2 = 4.0 
## 3.0 4.0 
 1.5 4.0 4.0   0

As linhas que começam com # são coloridas em vermelho como espero que você queira que sejam. sed apenas os grava quando uma s/// ubstitution for bem-sucedida. O script que o primeiro sed escreve para o segundo se parece com:

                bs1\.0
:i1\.0
i\
[41m## str2 = 1\.0 [0m\
[41m## 0\.0 1\.0 [0m
:s1\.0
s/0\.0/1\.0/gp;ti1\.0

                bs2\.0
:i2\.0
i\
[41m## str2 = 2\.0 [0m\
[41m## 1\.0 2\.0 [0m
:s2\.0
s/1\.0/2\.0/gp;ti2\.0

                bs3\.0
:i3\.0
i\
[41m## str2 = 3\.0 [0m\
[41m## 2\.0 3\.0 [0m
:s3\.0
s/2\.0/3\.0/gp;ti3\.0

                bs4\.0
:i4\.0
i\
[41m## str2 = 4\.0 [0m\
[41m## 3\.0 4\.0 [0m
:s4\.0
s/3\.0/4\.0/gp;ti4\.0

Note que embora pareça que as sequências de [ não são ignoradas, este é apenas o efeito do meu terminal na saída - que acaba comendo o caractere imediatamente após 3 . Quando o segundo sed receber o script, a entrada será como 3\[... , mas a saída i nsert para stdout será 3[...

    
por 12.03.2015 / 04:43
1

tente isto: Fuja de tudo. substituindo todo . a \.

str1="$( echo -n $i | sed 's/\./\\./g' )"  

repita o mesmo para str2 usando $ j . em seguida, substitua da seguinte forma

sed "s/$str1/$str2/g"
    
por 12.03.2015 / 08:36