Reemplazar todas las instancias de un personaje si ocurre antes de otro personaje

Reemplazar todas las instancias de un personaje si ocurre antes de otro personaje

Necesito poder exportar algunas variables de un archivo para poder usarlo en mi script BASH. el contenido del archivo es algo como esto:

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

Primero intenté obtenerlo sourcetal como está y recibí el mensaje de error que decía: command not found. Intenté usar export, lo que me dio un mensaje de error que decía: not a valid identifier.

Creo que sólo puedo exportar si cambio mi variable de my.variable.var1a my_variable_var1.
Puedo hacer esto cortando la línea en =y luego reemplazando todos .los s con _s y luego agregando las variables nuevamente.

Entonces mi pregunta es, ¿es posible cambiar?

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

a

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

¿Estás usando alguna de esas frases ingeniosas? Me encantaría usarlo, además de un buen aprendizaje.

Respuesta1

Con sed:

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

Es decir, reemplace una secuencia de caracteres que no sea .el comienzo de la línea seguida .de esa misma secuencia y _y repita el proceso hasta que ya no coincida.

Con awk:

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

Ahora, en caso de que el lado derecho de =contenga caracteres especiales del shell ( \"$&();'#~<>...`, espacio, tabulación, otros espacios en blanco...), es posible que desee citarlo. :

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

O:

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

Respuesta2

Usando bash:

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

Hemos utilizado un patrón de expansión de parámetros ${i//./_}para reemplazar todas .las s con _s en el nombre de la variable.

Ejemplo:

$ 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

Respuesta3

Aquí está otro sed:

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

Éste hace solo dos sustituciones, independientemente del número de puntos que preceden al =so con una entrada como:

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

el resultado es

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

Esto funciona bien cuando hay un =carácter por línea (como en su entrada de muestra).
Un enfoque más genérico que siempre reemplaza solo hasta el primero =(y solo si la línea contiene al menos uno =) incluso si hay varios =caracteres por línea:

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 =

o

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

entonces con una 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

produce:

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

información relacionada