Вот возможное решение более общей проблемы добавления строки к маркированному блоку текста (, т. е. строк текста, которые следуют за определенной меткой в файле и предшествуют следующей метке. или строку -из -файла ), только если строка еще не существует.
Простой подход состоит в том, чтобы просмотреть файл в обратном порядке, отслеживать последний раз, когда мы встречали строку , печатать ее каждый раз, когда мы встречаем определенную метку (, непосредственно перед печатью самой метки )., но только в том случае, если мы еще не видели(строка)и забываем, что встретили ее(строка)каждый раз, когда сталкиваемся с меткой. И, конечно же, в качестве последнего шага отмените результат.
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = 1
}
/^\[security\]$/ {
if ( ! seen ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
/^\[[^]]*\]$/ {
seen = 0
}
1' | tac
tac
, включенный в GNU Coreutils , объединяет и реверсирует файлы построчно. Как реверсировать файл с помощью других/стандартных инструментов описано в нескольких вопросах/ответах по U&L (, например, Как команда sed '1!G;h;$!d' реверсирует содержимое файла ? и Обратный поиск).
Это не будет вставлять force_https_protocol=PROTOCOL_TLSv1_2
после первого [security]
в следующем фрагменте текста:
[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
...
Чтобы просто вставить строку после каждого вхождения метки, если строка уже не существует,тот же подход может привести к:
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = NR
}
/^\[security\]$/ {
if ( ( NR == 1 ) || ! ( NR == seen + 1 ) ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
1' | tac
(Это будет вставлять force_https_protocol=PROTOCOL_TLSv1_2
после [security]
в приведенном выше текстовом образце ).
С помощью sed
вы можете использовать вариант цикла N;P;D;
(, который подробно описан в других вопросах/ответах по U&L; например:Как я могу использовать sed для замены многострочной строки -? или Как редактировать следующую строку после шаблона с помощью sed?).
Это вставит строку force_https_protocol=PROTOCOL_TLSv1_2
после строки, состоящей исключительно из [security]
, только если первой еще нет.
sed '
$! {
N
P
/^\[security\]\n/ {
/\nforce_https_protocol=PROTOCOL_TLSv1_2$/ b b
i\
force_https_protocol=PROTOCOL_TLSv1_2
}
:b
D
}
s/^\[security\]$/&\
force_https_protocol=PROTOCOL_TLSv1_2/'
Этот скрипт:
$!
), добавляет новую строку, за которой следует следующая строка, в пространство шаблонов (N
)(, которое уже содержит текущую строку ); P
); если эта строка [security]
... force_https_protocol=PROTOCOL_TLSv1_2
, просто удаляет первую строку из пространства шаблонов и запускает новый цикл (b b
,:b D
); force_https_protocol=PROTOCOL_TLSv1_2
на стандартный вывод(i\
)перед удалением первой строки из пространства шаблонов и запуском нового цикла(D
); [security]
, заменяет ее самой собой, за которой следует перевод строки и force_https_protocol=PROTOCOL_TLSv1_2
и печатает результат (посредством подразумеваемогоp
).