#awk #sed #ack
#awk #sed #ack
Вопрос:
У меня есть цепочка SSL-сертификатов, подобных этой
-----BEGIN CERTIFICATE-----
MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
CERT1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
CERT2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
CERT3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
CERT4
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDNjCCAtugAwIBAgIJAKpBxYNyH8biMAoGCCqGSM49BAMCMIGUMRQwEgYDVQQK
CERT5
-----END CERTIFICATE-----
и мне нужно удалить из него последний сертификат.
В macOS / BSD команда split
имеет флаг -p
для разделения по шаблону, и я использовал его:
cat cert | split -p "-----BEGIN CERTIFICATE-----"
cat xa{a,b,c,d}
Я полагаю, что в Linux тоже есть команда для выполнения этого в одной строке, но в Ubuntu команда split
не может разделяться по шаблону.
Мне нужно выполнить задание, используя стандартные команды Linux, такие как те, которые я пометил.
Ответ №1:
Этого решения GNU Sed должно быть достаточно:
sed -zE 's/(.*n)-----BEGIN CERTIFICATE-----.*/1/' your_input
-E
позволяет использовать(…)
вместо(…)
захвата чего-либо;-z
(доступно в GNU Sed) заключается в обработке всего ввода как одной длинной строки со встроеннымиn
s.
Поэтому первый .*
соответствует столько, сколько может (и захватывает его вместе с n
правом после него, чтобы он мог ссылаться на него при замене с помощью using 1
), если за ним следует n-----BEGIN CERTIFICATE-----
и что-либо еще после него (второе .*
).
Комментарии:
1. он удаляет последний
-----END CERTIFICATE-----
, но уверен, что он работает. Спасибо.2. @kyb, ты не хочешь его удалить? Тогда, пожалуйста, укажите желаемый результат в вашем вопросе.
3. Эта команда выводит 4 сертификата, удаляя 5-й. Это то, что я ищу. Но 4-й сертификат выглядит сломанным, потому что у него нет —— КОНЕЧНОГО СЕРТИФИКАТА —— . Я хотел бы видеть 4 действительных сертификата на выходе. (Конечно, его легко добавить вручную с
echo
помощью)4. @kyb Я исправил это (по предложению Эда, честно). В основном у меня был
(.*)n
, который не захватывал, удаляя, таким образом, последнюю новую строку в EOF, что требуется некоторыми редакторами VS (VS = очень глупо); изменение этого на(.*n)
сохранение последней новой строки в захваченной группе и, следовательно, в выходных данных, что делает этих редакторов счастливыми.5. да. теперь все работает так, как ожидалось. Спасибо. Я не знал об
-z
этом раньше.
Ответ №2:
Только с любым awk:
$ awk '/-----BEGIN CERTIFICATE-----/{printf "%s", rec; rec=""} {rec=rec $0 ORS}' file
-----BEGIN CERTIFICATE-----
MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
CERT1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
CERT2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
CERT3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
CERT4
-----END CERTIFICATE-----
или, если у вас есть tac
:
$ tac file | awk 'f; /-----BEGIN CERTIFICATE-----/{f=1}' | tac
-----BEGIN CERTIFICATE-----
MIICPjCCAeSgAwIBAgIRALMMpKnhRM2C7mnKI/rl8ggwCgYIKoZIzj0EAwIwgY4x
CERT1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIjCCAsegAwIBAgIOAMjnPM1wShDmOWUELuIwCgYIKoZIzj0EAwIwgagxCzAJ
CERT2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDIDCCAsWgAwIBAgIOAMjnPL8JUbVSmpMadWUwCgYIKoZIzj0EAwIwbDELMAkG
CERT3
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAqygAwIBAgIFFRCCEwYwCgYIKoZIzj0EAwIwgZQxFDASBgNVBAoMC0Ft
CERT4
-----END CERTIFICATE-----
Комментарии:
1. Есть ли у вас какие-либо идеи, на что жалуется OP с этим выводом? (См. Их Комментарий под моим вопросом.)
2. @Enrico Я подозреваю, что они используют редактор или какой-либо другой инструмент для проверки вывода, который отбрасывал / скрывал последнюю строку вашего вывода, потому что она не заканчивалась новой строкой (я знаю, что вы исправили это сейчас), поэтому для них эта последняя конечная строка отсутствовала.
3. Оооооо, я думал, что они ссылаются на исходную последнюю строку! Очевидно, они имели в виду ошибку, которую вы исправили в моем коде. Тогда еще раз спасибо.
4. Пожалуйста. Я просто предполагаю, что это то, о чем это было, конечно, но это кажется вероятным, и я не могу думать ни о чем другом!
Ответ №3:
Используя GNU awk
gensub
, вы можете попробовать следующее, написанное и протестированное только на основе показанных образцов.
awk -v RS="" -v regex="(.*)n(-----BEGIN CERTIFICATE-----.*)" '
{
print gensub(regex,"\1","1",$0)
}' Input_file
Комментарии:
1. Насколько я понимаю, RS =»» для «slurp mode», поэтому $ 0 содержит полный входной файл. Верно?
2. @kyb нет,
RS=""
(илиRS=''
) для «режима абзаца», где записи разделяются пустыми строками.RS='^$'
(если ваша версия awk поддерживает RS с несколькими символами) предназначен для «режима slurp», где $ 0 содержит полный входной файл. Они ведут себя аналогично, когда входные данные не содержат пустых строк (что, вероятно, является вашей ситуацией), за исключением того, что сRS=""
$0 не будет содержать последнюю новую строку в файле, в то время как сRS=''
ним будет. Чтобы увидеть разницу, попробуйтеecho 7 | awk -v RS='' '{print "<" $0 ">"}'
иecho 7 | awk -v RS='^$' '{print "<" $0 ">"}'
и обратите внимание на новую строку раньше>
в первом выводе.3. @EdMorton, спасибо, сэр, за разъяснение, извините, что я неправильно понял.