Bash while loop pesquisa e substitui usando sed

Bash while loop pesquisa e substitui usando sed

Tenho um problema com meu script a seguir (esta é a parte relevante):

#!/bin/bash

OLD=(
"_MAIN1_"
"_MAIN2_"
)

NEW=(
"#111"
"#222"
)

length=${#OLD[*]}

i=0

while (( i < length ))
do
  sed -e "s/${OLD[$i]}/${NEW[$i]}/g" oldfile.txt > newfile.txt

  #sed -e 's/_MAIN1_/#111/g' oldfile.txt > newfile.txt  # this works

  # Another way that does not work
  #sed -e 's/'"${OLD[$i]}"'/'"${NEW[$i]}"'/g' oldfile.txt > newfile.txt

  ((i++))
done

exit 0

Meu objetivo é substituir strings em um arquivo e salvá-lo em um novo. As strings "antigas" e "novas" são armazenadas em um array.

Tentei muitas coisas e brinquei com aspas simples e duplas - mas nada funcionou. Quando utilizo echoas variáveis, obtenho as strings corretas dentro do loop. Se duas strings explícitas forem definidas no sedcomando, isso funcionará bem.

Os padrões de string seguem aqueles em meus arrays de exemplo ('new' contém o sublinhado "_" e 'old' contém a hashtag "#").

Estou executando o bash em uma caixa Ubuntu 16.04.

Muito obrigado!

Responder1

Crie um sedscript que faça todas as substituições e aplique esse sedscript ao seu arquivo.

for (( i=0; i<${#OLD[@]}; ++i )); do
        printf 's/%s/%s/g\n' "${OLD[$i]}" "${NEW[$i]}"
done >script.sed

sed -f script.sed inputfile >outputfile && mv outptufile inputfile && rm script.sed

Dessa forma, você limita o número de vezes que precisa analisar o arquivo de entrada para um.

Para os dados fornecidos OLDe NEWo sedscript será gerado como

s/_MAIN1_/#111/g
s/_MAIN2_/#222/g

Responder2

Todo o seu script (que não funciona) pode ser substituído por uma única linha:

sed 's/_MAIN\([12]\)_/#\1\1\1/g' oldfile.txt > newfile.txt

Ou, de forma mais legível, mas equivalente:

sed 's/_MAIN1_/#111/g;s/_MAIN2_/#222/g' oldfile.txt > newfile.txt

Existem várias dezenas de outras maneiras de fazer isso, dependendo do seurealcaso de uso (por exemplo, de onde vêm os dados, como realmente são os valores, o que você está tentando fazer com os dados, etc.).

Responder3

Graças aRakesh Sharmacomentário de eu poderia resolver isso usando o -isinalizador no comando sed. Antes do loop, o backup do arquivo original é feito:

cp oldfile.txt oldfile.backup
while (( i < length ))
do
  sed -i -e 's/'"${OLD[$i]}"'/'"${NEW[$i]}"'/g' oldfile.txt
  ((i++))
done

Na próxima vez usarei Perl para manipulações de strings.

Editar:Adicionado ((i++))para evitar um loop infinito (graças aKusalanandacomentário).

informação relacionada