Ответ 1
Попробуйте следующее:
grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
Я использую следующую команду sed
для замены некоторых параметров в файле конфигурации:
sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
Теперь у меня есть одна проблема. Если строка не существует, я хочу добавить ее в нижнюю часть файла.
Я вызываю это с помощью popen
из программы на C. Я попытался использовать awk
.
Попробуйте следующее:
grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
Используя sed
, вы можете сказать:
sed -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename
Это заменит параметр, если он существует, иначе он добавит его в нижнюю часть файла.
Используйте параметр -i
, если вы хотите отредактировать файл на месте:
sed -i -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename
Как однострочный awk-единственный:
awk -v s=option=value '/^option=/{$0=s;f=1} {a[++n]=$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' file
ARGV [1] - ваш вход file
. Он открывается и записывается в цикл for
блока END
. Открытие file
для вывода в блоке END
заменяет необходимость в утилитах типа sponge
или записи во временный файл, а затем mv
временного файла на file
.
Два назначения массива a[]
накапливают все выходные строки в a
. if(!f)a[++n]=s
добавляет новый option=value
, если основной цикл awk не смог найти option
в file
.
Я добавил некоторые пробелы (не многие) для удобочитаемости, но вам действительно нужно всего одно место во всей awk-программе, пробел после print
.
Если file
включает # comments
, они будут сохранены.
здесь находится однострочный awk:
awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file
это не делает изменения на месте в файле, но вы можете:
awk '...' file > tmpfile && mv tmpfile file
sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
grep -q "option=value" /etc/fdm_monitor.conf || echo "option=value" >> /etc/fdm_monitor.conf
Здесь реализация awk
/^option *=/ {
print "option=value"; # print this instead of the original line
done=1; # set a flag, that the line was found
next # all done for this line
}
{print} # all other lines -> print them
END { # end of file
if(done != 1) # haven't found /option=/ -> add it at the end of output
print "option=value"
}
Запустите его, используя
awk -f update.awk < /etc/fdm_monitor.conf > /etc/fdm_monitor.conf.tmp && \
mv /etc/fdm_monitor.conf.tmp /etc/fdm_monitor.conf
или
awk -f update.awk < /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf
EDIT: Как однострочный:
awk '/^option *=/ {print "option=value";d=1;next}{print}END{if(d!=1)print "option=value"}' /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf
sed -i '1 h
1 !H
$ {
x
s/^option.*/option=value/g
t
s/$/\
option=value/
}' /etc/fdm_monitor.conf
Загрузите весь файл в буфер, в конце, измените все вхождения и, если никаких изменений не произошло, добавьте в конец
Я разработал решение kev grep/sed, установив переменные, чтобы уменьшить дублирование.
Задайте переменные в первой строке (подсказка: $_option
должна соответствовать всем в строке вверх до значения [включая любой разделитель типа = или:]).
_file="/etc/ssmtp/ssmtp.conf" _option="mailhub=" _value="my.domain.tld" \ sh -c '\ grep -q "^$_option" "$_file" \ && sed -i "s/^$_option.*/$_option$_value/" "$_file" \ || echo "$_option$_value" >> "$_file"\ '
Помните, что sh -c '...'
просто влияет на расширение области переменных без необходимости в export
. (См. Настройка переменной среды перед тем, как команда в bash не работает для второй команды в канале)
Вот однострочное седло, которое делает работу inline. Обратите внимание, что он сохраняет местоположение переменной и ее отступ в файле, когда он существует. Это часто важно для контекста, например, когда есть комментарии вокруг или когда переменная находится в отступом. Любое решение, основанное на парадигме "delete-then-append", плохо справляется с этим.
sed -i '/^[ \t]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf
С общей парой переменных/значений вы можете записать это следующим образом:
var=c
val='12 34' # it handles spaces nicely btw
sed -i '/^[ \t]*'"$var"'=/{h;s/=.*/='"$val"'/};${x;/^$/{s//c='"$val"'/;H};x}' test.conf
Наконец, если вы хотите также сохранить встроенные комментарии, вы можете сделать это с помощью группы catch. Например. если test.conf
содержит следующее:
a=123
# Here is "c":
c=999 # with its own comment and indent
b=234
d=567
Затем запустите этот
var='c'
val='"yay"'
sed -i '/^[ \t]*'"$var"'=/{h;s/=[^#]*\(.*\)/='"$val"'\1/;s/'"$val"'#/'"$val"' #/};${x;/^$/{s//'"$var"'='"$val"'/;H};x}' test.conf
Производит, что:
a=123
# Here is "c":
c="yay" # with its own comment and indent
b=234
d=567