Замените все экземпляры символа, если он встречается перед другим символом

Мне нужно иметь возможность экспортировать некоторые переменные из файла, чтобы я мог использовать его в моем сценарии 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 

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

3 Solutions collect form web for “Замените все экземпляры символа, если он встречается перед другим символом”

С 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 = -vq="'" -v OFS== ' {gsub(q, q "\\" qq) gsub(/\./, "_", $1) $2 = q $2 print $0 q}' 

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

 while IFS='=' read -rij; 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 -rij; 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 

Вот еще одно 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 

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

 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 
  • Поиск совпадений между двумя столбцами разных файлов и печать его в другом столбце
  • Объединение двух таблиц, включая многократное появление идентификаторов столбцов
  • unix: получить символы от 10 до 80 в файле
  • Получить файл CSV, содержащий имена файлов в каталоге?
  • Как вставить пробел каждые четыре символа в длинной строке?
  • Свернуть линию вертикально, чтобы каждое слово находилось на новой строке
  • Bash: подсчет значений значения в столбце x на основе значения в столбце y
  • Как я могу улучшить вывод find и grep?
  • Организовать записи в виде таблицы (csv) с помощью awk
  • Как я могу добавить # перед каждой строкой блока текста?
  • Условное предложение if в awk
  • Решение регулярного выражения grep (жадно не работает)
  • Linux и Unix - лучшая ОС в мире.