#shell #unix #awk #sed #freebsd
#оболочка #unix #awk #sed #freebsd
Вопрос:
Приведены два файла, первый — конфигурационный файл Apache:
$ cat vhosts-ssl.conf
<VirtualHost *:443>
vhost 1
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
<VirtualHost *:443>
vhost 2
foobar 2
barfoo 1
foobar 1
barfoo 2
</VirtualHost>
<VirtualHost *:443>
vhost 3
foobar 1
barfoo 1
foobar 2
barfoo 2
</VirtualHost>
<VirtualHost *:443>
vhost 4
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
И второй файл содержит строки, которые должны быть добавлены в конец одного (переменного) конкретного блока виртуального хоста:
$ cat inserted.txt
inserted line 1
inserted line 2
Результат должен выглядеть следующим образом:
$ cat vhosts-ssl.conf
<VirtualHost *:443>
vhost 1
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
<VirtualHost *:443>
vhost 2
foobar 2
barfoo 1
foobar 1
barfoo 2
inserted line 1
inserted line 2
</VirtualHost>
<VirtualHost *:443>
vhost 3
foobar 1
barfoo 1
foobar 2
barfoo 2
</VirtualHost>
<VirtualHost *:443>
vhost 4
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
Я попробовал это с некоторыми вариантами следующего sed, но это не помогло:
$ sed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf
Я не могу понять, как выбрать только один блок VirtualHost, в который мне нужно вставить файл, и поскольку я должен использовать FreeBSD sed (или awk), я также получаю эту ошибку с предыдущей командой sed:
$ sed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf
sed: 2: "}
": unused label 'a;n;/^</VirtualHost/!ba;r inserted.txt'
С помощью GNU sed я получаю этот вывод:
$ gsed -e '/^<VirtualHost/{:a;n;/^</VirtualHost/!ba;r inserted.txt' -e '}' vhosts-ssl.conf
<VirtualHost *:443>
vhost 1
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
inserted line 1
inserted line 2
<VirtualHost *:443>
vhost 2
foobar 2
barfoo 1
foobar 1
barfoo 2
</VirtualHost>
inserted line 1
inserted line 2
<VirtualHost *:443>
vhost 3
foobar 1
barfoo 1
foobar 2
barfoo 2
</VirtualHost>
inserted line 1
inserted line 2
<VirtualHost *:443>
vhost 4
foobar 1
foobar 2
barfoo 1
barfoo 2
</VirtualHost>
inserted line 1
inserted line 2
Поскольку я хотел бы понять свои ошибки и извлечь из них уроки, я бы предпочел ответы с некоторыми объяснениями и, возможно, даже некоторые ссылки на rtfm, спасибо.
Добавлено 2016-10-16
Псевдокод:
if BLOCK begins with /^<VirtualHost/
and ends with /^</VirtualHost/
and is the ${n-th} BLOCK
in FILE_1
then insert content of FILE_2
before last line of ${n-th} BLOCK
without touching rest of FILE_1
endif
save modified FILE_1
$ {n-й} собирается с помощью:
$ httpd -t -D DUMP_VHOSTS |
grep -i "${SUBDOMAIN}.${DOMAIN}" |
awk '/^[^ ]*:443[ ]*/ {print $3}' |
sed -e 's|((.*))|1|' |
cut -d: -f2
Вывод — это номер БЛОКА, который я хочу расширить на FILE_2
И, пожалуйста, только версии, отличные от GNU, поскольку я на FreeBSD, спасибо.
Комментарии:
1. Я добавил некоторый псевдокод
Ответ №1:
awk
на помощь!
требуется разделитель записей с несколькими символами, поддерживаемый gawk
$ awk 'NR==FNR{insert=$0; next}
{print $0 (FNR==2?insert:"") RT}' RS='^
прочитайте первый файл полностью и присвоите переменной insert, при повторении второго файла в конце второй записи выведите переменную после содержимого записи.
Другая версия для простого awk
$ awk 'NR==FNR{insert=insert?insert ORS $0:$0; next}
/</VirtualHost>/ amp;amp; c==2{print insert} 1' insert.file file
Комментарии:
1. @karakfa ... В последний раз, когда я видел твою репутацию, у тебя было 1500, что было год назад .. ты == неуклюжий !... хороший ответ ..lol
2. Хорошо, работает именно так, как мне нужно, но, как вы сказали, только с gawk.
3. Мне это нужно для FreeBSD awk.
4. Вторая версия делает это. Теперь я должен прочитать немного больше о awk, кажется, он более мощный, чем sed. Спасибо.
Ответ №2:
В GNU sed
(и BusyBox sed
) файл / метка / текст после a
, b
, c
, i
, r
, t
, w
, и :
команды могут быть разделены точкой с запятой, в то время как в других версиях sed
файл / метка / текст может быть разделен только новой строкой.
Такое поведение означает, что вместо определения метки a
первая строка определяет метку
a;n;/^</VirtualHost/!ba;r inserted.txt
и, как и при отдельном использовании -e
для закрывающей фигурной скобки, сценарий должен быть разделен как после метки, так и после ветки.
(кроме того, !
не должно быть экранировано)
sed -e '/^<VirtualHost/{:a' -e 'n;/^</VirtualHost/!ba'
-e 'r inserted.txt' -e '}' vhosts-ssl.conf
Альтернативно, сценарий может занимать несколько строк:
sed '/^<VirtualHost/ {
:a
n
/^</VirtualHost/!ba
r inserted.txt
}' vhosts-ssl.conf
Обратите внимание, что это разделение может не сработать в ситуациях, когда необходимо экранировать новую строку; например, при использовании команд a
, c
, и i
.
Комментарии:
1. Благодарим за объяснение различий в поведении метки.
Ответ №3:
Учитывая:
$ cat f1.txt
line 1
line 2
line 3
INSERT HERE
line 4
line 5
$ cat f2.txt
INSERTED LINE 1
INSERTED LINE 2
Вы можете сделать:
$ awk 'BEGIN{fc=""} FNR==NR{fc=fc $0 "n";next} /^INSERT HERE/{printf "%s", fc; next} 1' f2.txt f1.txt
line 1
line 2
line 3
INSERTED LINE 1
INSERTED LINE 2
line 4
line 5
Комментарии:
1. Хорошо, но у меня нет ничего, что я мог бы использовать как "ВСТАВИТЬ ЗДЕСЬ", см. Мои опубликованные vhosts-ssl.conf и недавно добавленный псевдокод.
insert.file RS="</VirtualHost>" file
прочитайте первый файл полностью и присвоите переменной insert, при повторении второго файла в конце второй записи выведите переменную после содержимого записи.
Другая версия для простого awk
Комментарии:
1. @karakfa … В последний раз, когда я видел твою репутацию, у тебя было 1500, что было год назад .. ты == неуклюжий !… хороший ответ ..lol
2. Хорошо, работает именно так, как мне нужно, но, как вы сказали, только с gawk.
3. Мне это нужно для FreeBSD awk.
4. Вторая версия делает это. Теперь я должен прочитать немного больше о awk, кажется, он более мощный, чем sed. Спасибо.
Ответ №2:
В GNU sed
(и BusyBox sed
) файл / метка / текст после a
, b
, c
, i
, r
, t
, w
, и :
команды могут быть разделены точкой с запятой, в то время как в других версиях sed
файл / метка / текст может быть разделен только новой строкой.
Такое поведение означает, что вместо определения метки a
первая строка определяет метку
a;n;/^</VirtualHost/!ba;r inserted.txt
и, как и при отдельном использовании -e
для закрывающей фигурной скобки, сценарий должен быть разделен как после метки, так и после ветки.
(кроме того, !
не должно быть экранировано)
Альтернативно, сценарий может занимать несколько строк:
Обратите внимание, что это разделение может не сработать в ситуациях, когда необходимо экранировать новую строку; например, при использовании команд a
, c
, и i
.
Комментарии:
1. Благодарим за объяснение различий в поведении метки.
Ответ №3:
Учитывая:
Вы можете сделать:
Комментарии:
1. Хорошо, но у меня нет ничего, что я мог бы использовать как «ВСТАВИТЬ ЗДЕСЬ», см. Мои опубликованные vhosts-ssl.conf и недавно добавленный псевдокод.