Заменить все вхождения символа, если он встречается перед другим символом

Заменить все вхождения символа, если он встречается перед другим символом

Мне нужно экспортировать некоторые переменные из файла, чтобы использовать их в моем скрипте BASH. Содержимое файла примерно такое:

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

Сначала я попытался использовать его sourceкак есть и получил сообщение об ошибке: command not found. Я попытался использовать export, что дало мне сообщение об ошибке: not a valid identifier.

Я думаю, что я могу экспортировать только если изменю свою переменную с my.variable.var1на my_variable_var1.
Я могу сделать это, обрезав строку at =и заменив все .s на _s, а затем добавив переменные обратно.

Итак, мой вопрос: возможно ли изменить:

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

к

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

используя любой из этих крутых "однострочников"? С удовольствием бы использовал это, плюс хорошее обучение.

решение1

С sed:

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

То есть заменить последовательность символов, отличную от .начала строки, на .ту же самую последовательность и _, и повторять процесс до тех пор, пока совпадения не исчезнут.

С awk:

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

Теперь, если правая часть содержит =специальные символы оболочки ( \"$&();'#~<>...`, пробел, табуляция, другие пробелы...), вы можете захотеть заключить ее в кавычки:

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

Или:

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

решение2

С использованием bash:

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

Мы использовали шаблон расширения параметров ${i//./_}, чтобы заменить все .s на _s в имени переменной.

Пример:

$ 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

решение3

Вот еще sed:

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

Этот пример делает только две замены, независимо от количества точек, предшествующих so, =при вводе следующего вида:

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

результат есть

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

Это работает нормально, когда в =строке один символ (как в вашем примере ввода).
Более общий подход, который всегда заменяет только до первого =(и только если строка содержит хотя бы один =), даже если в строке несколько =символов:

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 =

или

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

поэтому с такими входными данными, как:

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

выводит:

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

Связанный контент