#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