Попытка использовать sed для редактирования файла конфигурации из сценария bash для редактирования пары ключ / значение

#regex #bash #awk #sed #grep

#регулярное выражение #bash #awk #sed #grep

Вопрос:

У меня есть файл конфигурации, в котором есть пары ключ / значение по 1 на строку, которые мне нужно изменить из сценария bash. Это немного сложно, потому что есть определенная пара ключ / значение, которую мне нужно изменить, она может не существовать в файле, она может быть там, но пустой, или она может быть там, но уже заполнена, как указано ниже.

Пример фрагмента файла:

additional.urls=
cache.enable=true
compiler.cache_core=true

Мне нужно найти пару ключ / значение «дополнительные.urls =» и изменить его. Но это непросто, сначала строка может быть заполнена, или она может вообще не существовать в файле.

additional.urls=
или
additional.urls=https://myurl.me

Если пара ключ / значение пуста (ничего после =, за исключением, возможно, пробела), тогда я хочу добавить URL-адрес в конец строки:https://newurl.it:

additional.urls=https://newurl.it

Если все это отсутствует, я хочу вставить всю строку ключ / значение в файл, предпочтительно вверху, но это не имеет большого значения.

Тогда это становится сложнее, если у него уже есть значение (может быть 1 или более URL-адресов, разделенных запятыми) Мне нужно сохранить все, что уже есть, и добавить в конец строки, добавив запятую, а затем новый URL:

additional.urls=https://myurl1.me,https://myurl2.me
становится:
additional.urls=https://myurl1.me,https://myurl2.me,https://newurl.it

Я не могу понять, как это сделать. Если бы это был просто поиск и замена, я знаю, как это сделать, но условия сводят меня с ума. Возможно, sed — неправильный ответ, awk лучше или что-то еще? Я просто не знаю.

Ответ №1:

Это может сработать для вас (GNU sed):

 sed -zEi ':a;
          s#^additional.urls=.*#amp;,https://newurl.it#m;
          s/^(additional.urls=),/1/m;
          t;
          s/^/additional.urls=n/;
          ta' file
  

Переместите файл в память ( -z ), используйте расширенные регулярные выражения ( -E ) и отредактируйте на месте ( -i ).

Добавить ,https://newurl.it в начало строки additional.urls= .

Если начало строки additional.urls=, существует, удалите , .

Если любая из замен прошла успешно, отключитесь.

В противном случае вставьте additional.urls=n в начало файла и повторите.

Примечание. Использование m флага при заменах для многострочной обработки.

Команды могут быть сглажены:

 sed -zEi ':a;s#^additional.urls=.*#amp;,https://newurl.it#m;s/^(additional.urls=),/1/m;t;s/^/additional.urls=n/;ta' file
  

Комментарии:

1. По какой-то причине это всегда вставляет новую строку в начало файла. Если вы запустите его дважды, вы получите две строки в верхней части файла. Я пробую все предложения, а затем буду отлаживать как можно лучше. Спасибо.

Ответ №2:

Вы можете использовать это awk решение для выполнения всех 3 условий:

 awk -i inplace -v key='additional.urls' -v val='https://newurl.it' '
BEGIN {
   FS=OFS="="
}
$1 == key {
   $2 = ($2 ~ /^[[:blank:]]*$/ ? "" : $2 ",") val
   p = 1
}
END {
   if (!p)
      print key, val
} 1' file
  
 additional.urls=https://newurl.it
cache.enable=true
compiler.cache_core=true
  

Ответ №3:

 awk -F= -v add="additional.urls=test" '
    { a[$1]=$2 }
    END{ 
       split(add,b,"="); 
       a[b[1]]=(a[b[1]]~/^[[:blank:]]*/ ? "" : a[b[1]]",") b[2]; 
       OFS="="; 
       for(i in a){ print i,a[i] }}' configuration-file
  

.

 cache.enable=true
additional.urls=test
compiler.cache_core=true
  

Ответ №4:

sed предлагает через e переключение на код sh внутри sed. Посмотрите пример ниже и измените для своих нужд.

Сначала соответствующие слова будут назначены переменным a и b . Впоследствии они могут быть использованы в операторах if и switch .

 echo -e "foo=nbar=rabnzar=raz" | sed -E 's/(. )=(.*)/ a=1; b=2; if [[ $b ]]; then echo "$a=$b"; else case "$a" in foo) echo "$a=oof";; *) echo "$a=$(rev <<< $b)";; esac; fi/e'
  

Ответ №5:

В попытке сохранить все это читаемым, не пытаясь сделать слишком много в одном заявлении:

 if ! grep -q "additional.urls=" file
then
    # If line does not exist, add it at top.
    sed -i '1s/^/additional.urls=http://newurl.itn/' file
else
    #         If value is non-empty, add comma    Append newurl.it to end of the list
    sed -i -e "s/(additional.urls=. )/1,/" -e "s/(additional.urls=.*)/1http://newurl.it/" file
fi