Sed: полезные советы

21 Aug 2021

Всем известен потоковый редактор sed.

Как мы его используем чаще всего? Взять регулярку и заменить что-то на что-то глобально.

$ seq 1 10 | sed 's/1/one/'
one
2
3
4
5
6
7
8
9
one0

Только этим можно не ограничиваться так как это очень мощная штука с условными переходами и промежуточным буфером хранения.

Как работает типичный флоу:

 ____      -----------------------      ----
|file| -> |прочесть строку в буфер| -> |line|
 ----     |    (pattern space)    |     ----
    ^     -----------------------
    |                 \/
    |      -----------------------      -------------
    |     |  Выполнить команду 1  | -> |modified line|
    |      -----------------------      -------------
    |                 \/
    |                ....
    |                 \/
    |      -----------------------      -------------
    |     |  Выполнить команду N  | -> |modified line|
    |      -----------------------     | N-iteration |
    |                 \/                -------------
    |      -----------------------      -------------
    |     |   Записать результат  | -> |modified line|
    |      -----------------------     | N-iteration |
    |                 ||                -------------
    |                 \/
    |    --------------------------
    ----| повторить до конца файла |
         --------------------------

Под записью резльтата подразумевается не только вывод, но и запись в файл при in-place редактирвоании.

Стоп! А почему команд больше одной? Мы же с вам знаем только одно регулярное выражение?

Просто - sed умеет выполнять много команд и они разделаются точкой с запятой.

$ seq 1 10 | sed 's/1/one/;s/2/two/'
one
two
3
4
5
6
7
8
9
one0

Редактор так же умеет работать с двумя пространствами:

Как тут не вспомнить glutSwapBuffers() и методы вывода графики чтобы не мерцало.

sed дает нам возможность работать с промежуточным буфером читая в него и обменивая с текущим.

Существуют аналогичные команды в нижнем регистре, которые работаю игнорируя новую строку.

Пример.

% seq 1 10 | sed -n 'H;$!d;x;l;P'
\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10$

$ seq 1 10 | sed -n 'H;$!d;x;l;p'
\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10$

1
2
3
4
5
6
7
8
9
10

Команда:

Дополнительная команда.

Мы имеем дело с последовательностью. Поэтому не может быть каких-то вложенных команд.

Каждая команда может сопровождаться предусловием:

Зачем столько команд? Как пример - мультистроковая обработка файла. Проблема мультистрочкой обработки в том, что считывание в рабочий буфер осуществляется построчно.

$ seq 1 10 | sed -n '{H;$!d};x;s/^\n//;s/\n/:/g;p'
1:2:3:4:5:6:7:8:9:10

Ветвление.

Бывает условным и безусловным.

Безусловное.

echo 'abaaaaabababaaaaabbbb' | sed -n 's/aab/ab/; b end p; :end; p'
abaaaabababaaaaabbbb

Видим, что вывод результата произошел лишь один раз.

Условное.

echo 'abaaaaabababaaaaabbbb' | sed -n 's/abc/ab/; t end; p; :end; p'
abaaaaabababaaaaabbbb
abaaaaabababaaaaabbbb

Вывод командой p был сделан два раза.

На базе ветвлений можно сделать циклы.

Пример.

$ echo 'abaaaaabababaaaaabbbb' | sed -n ':repeat s/ab/ba/; t repeat;p'
bbbbbbbbaaaaaaaaaaaaa

Посмотрим что проиходит подробнее.

$ echo 'abaaaaabababaaaaabbbb' | sed -n ':repeat s/ba/ab/; p; t repeat;p'
aabaaaabababaaaaabbbb
aaabaaabababaaaaabbbb
aaaabaabababaaaaabbbb
aaaaababababaaaaabbbb
aaaaaabbababaaaaabbbb
aaaaaababbabaaaaabbbb
aaaaaaabbbabaaaaabbbb
aaaaaaabbabbaaaaabbbb
aaaaaaababbbaaaaabbbb
aaaaaaaabbbbaaaaabbbb
aaaaaaaabbbabaaaabbbb
aaaaaaaabbabbaaaabbbb
aaaaaaaababbbaaaabbbb
aaaaaaaaabbbbaaaabbbb
aaaaaaaaabbbabaaabbbb
aaaaaaaaabbabbaaabbbb
aaaaaaaaababbbaaabbbb
aaaaaaaaaabbbbaaabbbb
aaaaaaaaaabbbabaabbbb
aaaaaaaaaabbabbaabbbb
aaaaaaaaaababbbaabbbb
aaaaaaaaaaabbbbaabbbb
aaaaaaaaaaabbbababbbb
aaaaaaaaaaabbabbabbbb
aaaaaaaaaaababbbabbbb
aaaaaaaaaaaabbbbabbbb
aaaaaaaaaaaabbbabbbbb
aaaaaaaaaaaabbabbbbbb
aaaaaaaaaaaababbbbbbb
aaaaaaaaaaaaabbbbbbbb
aaaaaaaaaaaaabbbbbbbb
aaaaaaaaaaaaabbbbbbbb

Вредный совет

Как заменить пустую строку в начале файла?

sed -e '
   # ваш флоу по обработке мультилайна
   y/\n_/_\n/     ;# Обмен новой строки с подчеркиванием
   s/^[^_]*_//    ;# удаляем первое подчеркивание
   y/\n_/_\n/     ;# обращаем замену
' 

Литература:

Теги: shell linux обработка текста

Категории: HowTo