Substitua todas as instâncias de um personagem se ocorrer antes de outro personagem

Substitua todas as instâncias de um personagem se ocorrer antes de outro personagem

Preciso poder exportar algumas variáveis ​​de um arquivo, para poder usá-lo em meu script BASH. o conteúdo do arquivo é mais ou menos assim:

my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

Primeiro tentei obtê-lo usando sourcecomo estão e recebi a mensagem de erro dizendo: command not found. Tentei usar export, o que me deu uma mensagem de erro dizendo: not a valid identifier.

Acho que só consigo exportar se mudar minha variável de my.variable.var1para my_variable_var1.
Consigo fazer isso cortando a linha em =e substituindo todos .s por _s e adicionando as variáveis ​​novamente.

Então minha pergunta é: é possível mudar:

my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

para

my_variable_var1=a-long-ling.with.lot_of_different:characters:and_numbers
my_variable_another_var2=another-long-ling.with.lot_of_different:characters:and_numbers
my_variable_number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

usando algum daqueles 'one liners' legais? Adoraria usar isso, além de um bom aprendizado.

Responder1

Com sed:

sed -e :1 -e 's/^\([^=]*\)\./\1_/;t1'

Isso é substituir uma sequência de caracteres diferente .do início da linha seguida .pela mesma sequência e _e repetir o processo até que não corresponda mais.

Com awk:

awk -F = -v OFS== '{gsub(/\./, "_", $1); print}'

Agora, caso o lado direito =contenha caracteres especiais para o shell ( \"$&();'#~<>...`, espaço, tabulação, outros espaços em branco...), você pode querer citá-lo :

sed "s/'/'\\\\''/g;:1"'
     s/^\([^=]*\)\./\1_/;t1'"
     s/=/='/;s/\$/'/"

Ou:

awk -F = -v q="'" -v OFS== '
   {gsub(q, q "\\" q q)
    gsub(/\./, "_", $1)
    $2 = q $2
    print $0 q}'

Responder2

Usando bash:

while IFS='=' read -r i j; do echo "${i//./_}=$j" ; done

Usamos o padrão de expansão de parâmetros ${i//./_}para substituir todos .os s por _s no nome da variável.

Exemplo:

$ cat file.txt 
my.variable.var1=a-long-ling.with.lot_of_different:characters:and_numbers
my.variable.another.var2=another-long-ling.with.lot_of_different:characters:and_numbers
my.variable.number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

$ while IFS='=' read -r i j; do echo "${i//./_}=$j" ; done <file.txt 
my_variable_var1=a-long-ling.with.lot_of_different:characters:and_numbers
my_variable_another_var2=another-long-ling.with.lot_of_different:characters:and_numbers
my_variable_number3=yet_another_long-ling.with.lot_of_different:characters:and_numbers

Responder3

Aqui está outro sed:

sed 'h;s/\./_/g;G;s/=.*=/=/'

Este faz apenas duas substituições, independentemente do número de pontos anteriores ao =so com uma entrada como:

my.var.an.other.var.with.many.dots=line.with.many:chars:and_numbers.and.stuff

o resultado é

my_var_an_other_var_with_many_dots=line.with.many:chars:and_numbers.and.stuff

Isso funciona bem quando há um =caractere por linha (como na sua entrada de exemplo).
Uma abordagem mais genérica que sempre substitui apenas o primeiro =(e somente se a linha contiver pelo menos um =), mesmo se houver vários =caracteres por linha:

sed '/=/{                   # if line matches =
h                           # copy pattern space over the hold space
s/\./_/g                    # replace all . with =
G                           # append hold space content to pattern space
s/=.*\n[^=]*=/=/            # replace from the first = up to the first = after
}'                          # the newline character with a single =

ou

sed -e '/=/{h;s/\./_/g;G;s/=.*\n[^=]*=/=/' -e '}'

então com uma entrada como:

my.var.with.many.dots.but.no.equal.sign.and.stuff
my.var.with.many.dots=line.with.many:chars:numbers_and.stuff
other.var.with.many.dots=and.with.more.than=one.equal.sign=and.stuff

ele produz:

my.var.with.many.dots.but.no.equal.sign.and.stuff
my_var_with_many_dots=line.with.many:chars:numbers_and.stuff
other_var_with_many_dots=and.with.more.than=one.equal.sign=and.stuff

informação relacionada