Регулярні команди та команди з командою sed. Вивчаємо команди Linux: sed Sed пошук за регулярним виразом


Автор: Rares Aioanei
Дата публікації: 19 листопада 2011 року
Переклад: А. Кривошей
Дата перекладу: липень 2012 р.

1. Введення

Ласкаво просимо до другої частини нашої серії, яка присвячена sed, версії GNU. Існує декілька версій sed, які доступні на різних платформах, але ми сфокусуємось на GNU sed версії 4.x. Багато хто з вас чув про sed, або вже використовували його, швидше за все як інструмент заміни. Але це тільки одне із призначень sed, і ми постараємося показати вам усі аспекти використання цієї утиліти. Його назва розшифровується як "Stream EDitor" і слово "stream" (потік) в даному випадку може означати файл, канал або просто stdin. Ми сподіваємося, що у вас вже є базові знання про Linux, а якщо ви вже працювали з регулярними виразами, або принаймні знаєте, що це таке, то все для вас буде набагато простіше. Обсяг статті не дозволяє включити до неї повний посібник із регулярних виразів, натомість ми озвучимо базові концепції та дамо велику кількість прикладів використання sed.

2. Встановлення

Тут не треба багато розказувати. Швидше усі sed у вас вже встановлено, тому що він використовується різними системними скриптами, а також користувачами Linux, які хочуть підвищити ефективність своєї роботи. Ви можете дізнатися, яка версія sed у вас встановлена ​​за допомогою команди:

$ sed --version

У моїй системі ця команда показує, що я маю GNU sed 4.2.1 плюс дає посилання на домашню сторінку програми та інші корисні відомості. Пакет називається "sed" незалежно від дистрибутива, крім Gentoo, де він присутній неявно.

3. Концепції

Перед тим, як йти далі, ми вважаємо за важливе акцентувати увагу на тому, що робить "sed", тому що словосполучення "потоковий редактор" мало що говорить про його призначення. sed приймає на вході текст, виконує задані операції над кожним рядком (якщо не задано інше) та виводить модифікований текст. Зазначеними операціями можуть бути додавання, вставка, видалення або заміна. Це не так просто, як виглядає: попереджаю, що є велика кількість опцій та їх комбінацій, які можуть зробити команду sed дуже важкою для розуміння. Тому ми рекомендуємо вивчити основи регулярних виразів, щоб розуміти, як це працює. Перед тим, як приступити до керівництва, ми хотіли б подякувати Eric Pement та іншим за натхнення та за те, що він зробив для всіх, хто хоче вивчати та використовувати sed.

4. Регулярні вирази

Оскільки команди (скрипти) sed для багатьох залишаються загадкою, ми відчуваємо, що наші читачі повинні розуміти базові концепції, а не сліпо копіювати та вставляти команди, значення яких вони не розуміють. Коли людина хоче зрозуміти, що є регулярними виразами, ключовим словом є "відповідність", або, точніше, "шаблон відповідності". Наприклад, у звіті для свого департаменту ви написали ім'я Nick, звертаючись до мережного архітектора. Але Nick пішов, а на його місце прийшов John, тому тепер ви повинні замінити слово Nick John. Якщо файл зі звітом називається report.txt, ви повинні виконати таку команду:

$ cat report.txt / sed "s/Nick/John/g" > report_new.txt

За промовчанням sed використовує stdout, ви можете використовувати оператор перенаправлення виводу, як показано в прикладі вище. Це дуже простий приклад, але ми проілюстрували кілька моментів: ми шукаємо всі відповідності шаблону Nick і замінюємо у всіх випадках на John. Зазначимо, що sed здійснює пошук з урахуванням регістру, тому будьте уважні та перевірте вихідний файл, щоб переконатися, що всі заміни були здійснені. Наведений вище приклад можна було записати і так:

$ sed "s/Nick/John/g" report.txt > report_new.txt

Добре, скажете ви, але де тут регулярні висловлювання? Так, ми хотіли спочатку показати приклад, а тепер починається найцікавіша частина.
Якщо ви не впевнені, чи написали ви "nick" або "Nick", і хочете передбачити обидва випадки, необхідно використовувати команду sed "s/Nick/nick/John/g". Вертикальна риса має значення, яке ви повинні знати, якщо вивчали C, тобто ваше вираз буде відповідати "nick" або "Nick". Як ви побачите нижче, канал може використовуватися й іншими способами, але сенс залишається той самий. Інші оператори, що широко використовуються в регулярних виразах - це "?", який відповідає повторенню попереднього символу нуль або один раз (тобто flavou?r буде відповідати flavor і flavour), "*" - нуль або більше разів, "+" - один або більше разів. "^" відповідає початку рядка, а "$" - навпаки. Якщо ви - користувач vi або vim, багато речей здадуться вам знайомими. Зрештою, ці утиліти, разом з awk і C йдуть корінням в ранні дні UNIX. Ми не будемо більше говорити на цю тему, тому що простіше зрозуміти значення цих символів на прикладах, але ви повинні знати, що існують різні реалізації регулярних виразів: POSIX, POSIX Extended, Perl, а також різні реалізації нечітких регулярних виразів, що гарантують вам головний біль .

5. Приклади використання sed

Синтаксис команди Опис
sed "s/Nick/John/g" report.txt Замінює кожне входження Nick на John у файлі report.txt
sed "s/Nick/nick/John/g" report.txt Замінює кожне входження Nick або nick John.
sed "s/^/ /" file.txt >file_new.txt Додає 8 пробілів ліворуч від тексту для покращення якості друку.
sed -n "/Of course/,/attention you \
pay/p" myfile
Виводить один абзац, що починається з "Of course" і закінчується на "attention you pay"
sed -n 12,18p file.txt Виводить лише рядки 12-18 файлу file.txt
sed 12,18d file.txt Виводить весь файл file.txt за винятком рядків з 12 до 18
sed G file.txt Подвоює прогалини в file.txt
sed -f script.sed file.txt Записує всі команди в script.sed та виконує їх.
sed "5!s/ham/cheese/" file.txt Замінює гачок на cheese в file.txt за винятком 5-го рядка
sed "$d" file.txt Видаляє останній рядок
sed "/\(3\)/p" file.txt Друкує лише рядки з трьома послідовними цифрами
sed "/boom/!s/aaa/bb/" file.txt Якщо знайдено "boom", замінити aaa на bb
sed "17,/disk/d" file.txt Видаляє всі рядки, починаючи з 17-го, до "disk"
echo ONE TWO / sed "s/one/unos/I" Замінює one на unos незалежно від регістру, тому буде надруковано "unos TWO"
sed "G; G" file.txt Потроює прогалини у файлі
sed "s/.$//" file.txt Спосіб заміни dos2unix:)
sed "s/^[^t]*//" file.txt Видаляє всі прогалини перед кожним рядком у file.txt
sed "s/[^t]*$//" file.txt Видаляє всі прогалини в кінці кожного рядка в file.txt
sed "s/^[^t]*//;s/[^]*$//" file.txt Видаляє всі прогалини на початку та в кінці кожного рядка у file.txt
sed "s/foo/bar/" file.txt Замінює foo на bar лише у першому входженні у рядку.
sed "s/foo/bar/4" file.txt Замінює foo на bar тільки у четвертому входженні у рядку.
sed "s/foo/bar/g" file.txt Замінює foo bar для всіх входжень у рядку.
sed "/baz/s/foo/bar/g" file.txt Замінити foo на bar, тільки якщо рядок містить baz.
sed "/./,/^$/!d" file.txt Видалити всі послідовні порожні рядки за винятком EOF
sed "/^$/N;/\n$/D" file.txt Видалити всі послідовні порожні рядки, але залишити верхній порожній рядок.
sed "/./,$!d" file.txt Видалити всі початкові порожні рядки
sed -e:a -e "/^\n*$/($d;N;);/\n$/ba" \
file.txt
Видалити всі замикаючі порожні рядки
sed -e:a -e "/\\$/N; s/\\n//; ta" \
file.txt
Якщо файл закінчується зворотним сплешем, з'єднайте його з наступним (корисно для скриптів оболонки)
sed "/regex/,+5/expr/" Відповідає regex плюс 5 наступних рядків
sed "1~3d" file.txt Видалити кожен третій рядок, починаючи з першого.
sed -n "2~5p" file.txt Друкувати кожен п'ятий рядок, починаючи з другого.
sed "s/ick/John/g" report.txt Інший спосіб запису деяких наведених вище прикладів. Ви можете запропонувати свій?
sed -n "/RE/(p;q;)" file.txt Друкує лише перша відповідність RE (регулярного виразу)
sed "0,/RE/(//d;)" file.txt Видаляє лише першу відповідність
sed "0,/RE/s//to_that/" file.txt Змінює лише першу відповідність
sed "s/^[^,]*,/9999,/" file.csv Замінює перше поле на 9999 у CSV-файлі
s/^ *\(.*[^ ]\) *$//\1//; s/"*, */"//g; : loop s// *\([^",/][^,/]*\) *, *//\1//g; s// *, *//\1//g; t loop s / *////g; s// *///g; s/^/\(.*\)/$/\1/; Скрипт sed для конвертування CSV-файлу у файл з вертикальною рисою як роздільник (працює тільки з деякими типами CSV, з вбудованими лапками та комами).
sed ":a;s/\(^\/[^0-9.]\)\(\+\)\(\(3\)\)/\1\2,\3/g;ta" file .txt Змінює формат чисел у file.txt з 1234.56 на 1.234.56
sed -r "s/\<(reg/exp)+/\U&/g" Перекладає будь-яке слово, що починається з reg або exp у верхній регістр.
sed "1,20 s/Johnson/White/g" file.txt Здійснює заміну Johnson на White тільки в рядках 1 - 20.
sed "1,20 !s/Johnson/White/g" file.txt Попередній приклад навпаки (замінює скрізь, крім рядків 1-20)
sed "/from/,/until/ ( s/\ /magenta/g; \ s/\ /cyan/g; )" file.txt Замінює тільки між "from" та "until"
sed "/ENDNOTES:/,$ ( s/Schaff/Herzog/g; \s/Kraft/Ebbing/g; )" file.txt Замінює тільки зі слова "ENDNOTES:" та до EOF
sed "/./(H;$!d;);x;/regex/!d" file.txt Друкує абзац лише якщо він містить regex
sed -e "/./(H;$!d;)" -e "x;/RE1/!d;/RE2/!d;/RE3/!d" file.txt Друкує абзаци тільки якщо вони містять RE1, RE2 та RE3
sed "s/14"/fourteen inches/g" file.txt Так ви зможете використовувати подвійні лапки
sed "s/\/some\/UNIX\/path/\/a\/new\/path/g" file.txt Робота з шляхами Unix
sed "s///g" file.txt Видаляє всі символи, починаючи з a до g з файлу file.txt
sed "s/\(.*\)foo/\1bar/" file.txt Замінює лише останню відповідність foo на bar
sed "1!G;h;$!d" Заміна команди tac
sed "/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//" Заміна команди rev
sed 10q file.txt Заміна команди head
sed -e:a -e "$q;N;11,$D;ba" \ file.txt Заміна команди tail
sed "$!N; /^\(.*\)\n\1$/!P; D" \ file.txt Заміна команди uniq
sed "$!N; s/^\(.*\)\n\1$/\1/;\ t; D" file.txt Зворотна команда (що еквівалентно uniq-d)
sed "$!N;$!D" file.txt Еквівалент tail -n 2
sed -n "$p" file.txt ... tail -n 1 (або tail -1)
sed "/regexp/!d" file.txt Еквівалент grep
sed -n "/regexp/(g;1!p;);h" file.txt Друкує рядок, що знаходиться перед першою відповідністю регулярному виразу, але не включає саму відповідність
sed -n "/regexp/(n;p;)" file.txt Друкує рядок, що знаходиться після першої відповідності регулярному виразу, але не включає саму відповідність
sed "/pattern/d" file.txt Видаляє рядки, що відповідають шаблону pattern
sed "/./!d" file.txt Видаляє всі порожні рядки з файлу
sed "/^$/N;/\n$/N;//D" file.txt Видаляє всі наступні один за одним порожні рядки, за винятком перших двох
sed -n "/^$/(p;h;);/./(x;/./p;)"\ file.txt Видаляє останній рядок кожного абзацу
sed "/^$/q" Отримує заголовок листа
sed "1,/^$/d" Отримує тіло листа
sed "/^Subject: */!d; s///;q" Отримує тему листа
sed "s/^/> /" Цитує повідомлення, вставляючи ">" перед кожним рядком
sed "s/^> //" Зворотна команда (прибирає цитування із повідомлення)
sed -e:a -e "s/<[^>]*>//g;/ Видаляє HTML-теги
sed "/./(H;d;);x;s/\n/=(NL)=/g" file.txt / sort \ / sed "1s/=(NL)=//;s/=( NL)=/\n/g" Сортує абзаци у file.txt в алфавітному порядку
sed "s@/usr/bin@&/local@g" path.txt Замінює /usr/bin на /usr/bin/local path.txt
sed "s@^.*$@<<<&>>>@g" path.txt Спробуйте та побачите:)
sed "s/\(\/[^:]*\).*/\1/g" path.txt За умови, що path.txt містить $PATH, виводить лише перший шлях у кожному рядку
sed "s/\([^:]*\).*/\1/" /etc/passwd Заміна awk - показує лише користувачів із файлу passwd
echo "Welcome To The Geek Stuff" / sed \ "s/\(\b\)/\(\1\)/g" (W)elcome (T)o (T)he (G)eek (S)tuff Зрозуміло без пояснень
sed -e "/^$/,/^END/s/hills/\ mountains/g" file.txt Замінює "hills" на "mountains", але тільки в блоках тексту, що починаються з порожнього рядка і закінчуються рядком із трьома символами "END", включно.
sed -e "/^#/d" /etc/services / more Показує файл services без закоментованих рядків
sed "$s@\([^:]*\):\([^:]*\):\([^:]*\)@\3:\2:\1@g" path.txt Змінює порядок елементів у останньому рядку файлу path.txt на зворотний
sed "/regex/(x;p;x;)" file.txt Вставляє новий рядок вище кожного рядка, що відповідає регулярному виразу
sed "/AAA/!d; /BBB/!d; /CCC/!d" file.txt Шукає відповідність AAA, BBB та CCC у будь-якому порядку
sed "/AAA.*BBB.*CCC/!d" file.txt Шукає відповідність AAA, BBB та CCC у заданому порядку
sed -n "/^.\(65\)/p" file.txt Друкує рядки довжиною 65 і більше символів
sed -n "/^.\(65\)/!p" file.txt Друкує рядки довжиною 65 символів і менше
sed "/regex/G" file.txt Вставляє порожній рядок під кожним рядком
sed "/regex/(x;p;x;G;)" file.txt Вставляє порожній рядок над та під кожним рядком
sed = file.txt / sed "N;s/\n/\t/" Нумерує рядки у file.txt
sed -e:a -e "s/^.\(1,78\)$/ &/;ta" file.txt Вирівняти текст з правого краю
sed -e:a -e "s/^.\(1,77\)$/ &/;ta" -e "s/\(*\)\1/\1/" file.txt Вирівняти текст по центру

6. Висновок

Це тільки частина того, що можна було б розповісти про sed, але дана серія статей є скоріше практичним посібником, який, як ми сподіваємося, допоможе вам оцінити всю міць утиліт Unix і зробить вашу роботу більш ефективною.

sed обробляє потік послідовно, рядок за рядком, починаючи з першого і закінчуючи останнім (звичайно якщо в sed-скрипті не зазначено іншого, наприклад можна обробляти тільки перші рядки, і завершити обробку після виконання якоїсь умови), зазвичай кожен рядок обробляється окремо, у три етапи.

Важливо

Нижченаведена схема надалі часто згадуватиметься, наприклад " першому етапі обробки рядка " таки означає - перший етап із цієї схеми.

Процедура 2.1. Обробка тексту утилітою sed.

    На цьому етапі рядок завантажується у буфер. Буфером називається виділена sed область пам'яті, розмір якої не обмежений (для GNU версії sed, звичайно на практиці розмір обмежений обсягом оперативної, і swap-пам'яті).

    Завантаження закінчується після читання з потоку символу нового рядка (\n) або після завершення потоку. При цьому символ нового рядка хоч і читається із потоку, проте не пишеться у буфер.

    Обробка рядка.

    На цьому етапі виконується sed-скрипт, причому вміст буфера зазвичай змінюється. sed-скрипт складається з особливих sed-команд, кожна з яких є однією з букв латинського алфавіту. Як завжди, малі та ВЕЛИКІ літери різняться: nі Nце різні команди. Найпростіше записувати sed-команди в командному рядку, відразу після sed та її ключів, наприклад:

    Sed -n "p;p;p"

    Для розділення команд використовується крапка з комою (;).

    Застереження

    Якщо ви пишете скрипти прямо після команди, то завжди укладайте їх в одиночні "лапки", справа в тому, що тільки в цьому випадку оболонка не оброблятиме ці скрипти, в деяких випадках допустимо використовувати подвійні лапки, наприклад якщо ви хочете внести всередину скрипта shell -Змінну, проте при цьому будьте уважні: shell спробує розкрити багато службових символів у вашому скрипті.

    Підказка

    Якщо всередині скрипта вам необхідно використовувати символ одиночної лапки, то ви можете скористатися її шістнадцятковим уявленням: « \x27 ».

    Команди sed можуть змінити вміст буфера, але крім того, як і в інших мовах програмування, у sed-скриптах можна застосовувати команди умовних та безумовних переходів ( b , t, і T), є також команди переривання роботи ( qі Q). Деякі команди впливають не тільки на етап обробки рядка, але й на інші етапи, крім того, всередині скрипту можна ввести ще один або кілька рядків із вхідного потоку (як на першому етапі).

    Важливо

    Потрібно розуміти, що sed працює з потоком, а не з файлом, вона переглядає рядки лише послідовно, від початку до кінця. Тому неможливо прочитати десятий рядок після двадцятого – якщо в цьому є необхідність, слід зберегти десятий рядок під час його обробки. Також неможливо дізнатися, що цей рядок є наприклад передостанньою, не дивлячись на те, що цілком можна визначити номер рядка від початку потоку. Можна з'ясувати, що цей рядок є останнім, але тільки в момент його обробки.

    Перед (майже) будь-якою командою sed ви можете поставити адресний вираз, у такому разі команда виконається тоді, і тільки тоді, коли адресний вираз істинний. Як адресний вираз можна використовувати

    Номер рядка Тоді команда виконається тільки для того рядка, номер якого вказано Діапазон номерів рядківКоманда виконається для всіх рядків із зазначеного діапазону (діапазон вказується через кому, замість другого числа допустимо вказувати `$", цей символ позначає останній рядок. Регулярний вираз

    Команда виконається тільки якщо в буфері знайдеться RE.

    Комбінований діапазон.

    Можна створити більш складне умова, наприклад від заданого RE, і до рядка $ (до кінця). Або від першого RE до другого (включно).

    Зауваження

    Рядки у sed нумеруються з одиниці. Спочатку виконується пошук рядка, в якому є збіг з першою адресою діапазону, для цього рядка виконується команда. Починаючи з наступного рядка здійснюється пошук другої адреси діапазону. Однак, для першого рядка таку поведінку можна змінити: якщо записати не `1, RE", а `0, RE", то регулярне вираз буде перевірятися так само і в першому рядку.

    Підказка

    Якщо ви хочете, щоб один адресний вираз діяло відразу не кілька команд, тоді укласти ці команди (фігурні дужки).

    Зауваження

    Допустимі вкладені блоки, крім того, допустимо всередині блоку використовувати адресні вирази у т.ч. та для вкладених блоків.

    Крім написання скрипта відразу після команди, ви можете записати його у файл, для виконання такого файлу можна використовувати опцію -f, наприклад:

    $ sed -f my_script.sed test_file.txt

    Ця команда виконає sed-скрипт my_script.sed для файлу test_file.txt. Крім того, використовуючи sha-bang

    #!/bin/sed -f

    ви можете змусити виконувати ваші скрипти оболонку, наприклад, якщо ви дописали до вашого скрипта в перший рядок цей sha-bang, і крім того у вас є право виконання цього скрипта, то попередній приклад можна виконати так:

    $./my_script.sed test_file.txt

    Застереження

    Перший час, я б рекомендував записувати в файли всі sed-скрипти з тих, в яких більше однієї команди. По-перше їх зрозуміти набагато простіше, по-друге вони таким чином зберігаються, і по-третє їх набагато зручніше редагувати. Крім того, у sed-файлах ви можете використовувати будь-які лапки. Слід також врахувати, що деякі команди необхідно записувати останніми в рядку, що часто неможливо, якщо один рядок. І нарешті, у файлі ви можете використовувати коментарі, які дозволять вам швидко пристосувати готовий скрипт для нового застосування.
  1. Виведення буфера

    Після завершення роботи скрипта sed виводить вміст буфера у вихідний потік. Однак це далеко не завжди необхідно, якщо вам це не потрібно, скористайтеся опцією -n, яка блокує виведення буфера. Крім того, на цьому етапі відбувається висновок і деякої іншої інформації, якщо в скрипті виконалися команди a , c, та/або i. Ці команди теж виводять інформацію у вихідний потік, але не під час виконання, а на цьому етапі. Існують три команди ( d , Dі Q), які також пригнічують виведення буфера цьому етапі.

Перші sed-скрипти.

Для початку вивчення sedнам знадобиться якийсь простий текст, наприклад цей:

приклад 2.1. Текст, який використовується для перевірки скриптів.

Ви можете пожертвувати невелику суму яндекс-грошей на рахунок 41001666004238 для оплати хостингу, інтернету та іншого. Це, звичайно, добровільно, проте це набагато покращить цей документ (у мене буде більше часу для його покращення). Насправді проект часто перебуває на межі закриття, бо жодних грошей ніколи не приносив, і приносити не буде. Ви можете мені допомогти. Дякую.

Утиліта sedце потужний потоковий редактор тексту із підтримкою регулярних виразів. За допомогою sedви можете замінювати шаблони тексту (причому безпосередньо у файлі!), видаляти рядки (елементи масиву), виводити відповідні маски рядки (подібно grep). Редактор sedпідтримує застосування кількох команд та розширений синтаксис регулярних виразів (при якому не потрібно екранувати спец. символи).

У sed немає підтримки випереджаючих та ретроспективних перевірок у регулярках! Для заміни з використанням розширеного синтаксису regex використовуйте:

Увага!

Досить проблемно працювати з символом перекладу рядка! Найзручніше рішення — це:

Як роздільники можна використовувати будь-які символи (наприклад: ,). Matchчастини (які усередині круглих дужок) доступні як, .

Опції утиліти:

Прапори рядки-команди (вказувати наприкінці маски):

Приклади

Фільтрування рядків

Вивести рядки 1-5:

Вивести файли відповідні масці:

Рядки довші за 80 символів:

Заміна за шаблоном

Вивести входження ( matches) через табуляцію:

Замінити назви файлів ( composerна composer-dev):

Замінити символи (regex):

Замінити URL у файлі (штука в роздільниках, і для заміни у файлі):

Замінити параметр у конфізі:

Видалити початкові прогалини (аналог ltrim):

Видалення рядків

Видалити з файлу рядок відповідного шаблону:

Видалити перший рядок виводу:

Видалити рядки від першого до відповідного regex:

Замінити підрядок:

Примітка

За замовчуванням потрібно екранувати всі спец. символи в regex'ах, що дуже ускладнює читання масок. Для того, щоб екранувати спец.символи тільки у випадку опису в тексті їх самих - увімкніть розширений режим regexвиразів за допомогою опції.

Видалити порожні рядки:

Видалити останні N=2 символи:

Вилучення підрядків

Вирізати / запам'ятати останні N=4 символи:

#sed, #regexp, #bash

Вивчаємо команди Linux: sed

Поточний редактор SED

Sed – легкий (бінарник важить всього 128 кілобайт) та зручний інструмент обробки тексту.

У цій статті я наведу кілька простих прикладів використання sedі розповім про його основні можливості.

Sed отримує вхідний потік даних або файл рядково, редагує кожен рядок згідно з правилами, визначеними в sed-скрипті, а потім виводить результат. Sed це тьюрінг-повна мова програмування.

Формат команди sed

Команда sed має формат:

sed [ -n ] [ -e скрипт ] [ -f скрипт-файл ] [ файли ]

Прапор -nпригнічує висновок
-e- Вказує на список інструкцій, заданий у командному рядку.
-f- Вказує місцезнаходження файла-скрипта.

Формат команд редагування

Скриптовий файл складається з набору команд:

[ адреса [ , адреса ] ] команда [ аргументи ]

по одному у кожному рядку.
Адреси це або номери рядків, або спеціальні символи, або регулярний вираз:

$ - останній рядок
початок~N- Кожна N-я рядок, починаючи з номера початок
/регулярний_вираз/- Рядки, що потрапляють під регулярний_вираз
Приклади:

1~2 - Кожен другий рядок /REGEXP/- усі рядки, в яких зустрічається /REGEXP/ 10,20 - рядки з 10-го по 20-те 10,+10 - рядки з 10-го по 20-те 5,~N- рядки починаючи з 5-го і до першого, кратного N 5,/REGEXP/- рядки, що містять /REGEXP/, після 5-ї (не включаючи 5-ю)
  • Якщо адреса не вказана, обробляються всі рядки.
  • Якщо вказана одна адреса - обробляється відповідний рядок
  • Якщо вказано дві адреси, вибираються рядки в заданому інтервалі.
  • !команда- Виконується командадля рядків, які не були вибрані за адресами.

Основні команди

Розглянемо основні команди:

[адреса] a текст- додати новий рядок із текстом після зазначеного рядка

[адреса [, адреса]] c текст- Видаляє вибрані рядки та замінює їх на текст

[адреса [, адреса]] d- Видаляє зазначені рядки.

[адреса] i текст- Вставити текстна місце вказаного рядка.

[адреса [, адреса]] p(з прапором -n) виводить знайдені рядки.

[адреса] q- Вихід із sed.

[адреса [, адреса]] r файл- Читає файлта видає його зміст на вихід.

[адреса [, адреса]] s/регулярний_вираз/заміна/прапори- Замінює регулярний_виразна заміна-у з урахуванням прапорів:

  • g - у всьому рядку
  • i - без урахування регістру
  • p - виводити результат заміни

[адреса [, адреса]] y/рядок1/рядок2/- Замінює всі входження символів у рядку1відповідними символами з рядки2.

Довжини рядків мають бути однаковими.

[адреса [, адреса]] ( команди )- дужки групують команди
[адреса] =- Видає номери рядків

Мітки

: мітка- зіставити групі команд мітку
b мітка мітка, якщо міткавідсутня, то перехід у кінець командного файлу.

t мітка- перехід до команди, позначеної міткою міткатільки після вдалої заміни за допомогою команди s///

Цикл виконання

sed працює з двома буферами даних: основним та допоміжним. Спочатку обидва буфери порожні.
Робота з цими буферами здійснюється за допомогою команд: \'h', `H', `x', `g', `G' `D' h- Замінити вміст допоміжного буфера вмістом основного
H- Додати новий рядок до допоміжного буфера і потім додати вміст основного буфера до допоміжного вмісту
x- Поміняти вміст обох буферів подекуди
g- Замінити вміст основного буфера вмістом допоміжного
G- Додати новий рядок до основного буфера і потім додати вміст допоміжного буфера до основного вмісту
D- Видалити текст основного буфера до наступного символу перекладу рядка
N- Додати новий рядок до основного буфера, потім додати туди наступний рядок, що обробляється
P- Вивести вміст основного буфера до символу перекладу рядка.

Більш складні приклади

Наступний скрипт змінює місцями рядки файлу (перші рядки стають останніми і навпаки)

Вважаємо рядки файлу (виводимо номер останнього рядка)

результат

Звернення рядків

Цей скрипт переміщує дві літери за один раз.

додаткова інформація

Детальніше про формат sed-скриптів можна дізнатися, прочитавши мануал man sedабо технічну документацію info sed.

Повернутись до змісту

02.02.2013

Розкладання рядків засобами Bash у прикладах (parameter expansions)

(Використовувалися матеріали [1] [2] та [3])

Для роботи над рядками засобами Bash використовуються параметри розкладання ( parameter expansions) Опис цього принципу можна знайти в пункті.
Опис важкувато для розуміння. Набагато простіше зрозуміти принцип роботи на прикладах.

1. Видалення символів на початку або в кінці рядка

Будь-який одиночний символ позначається як

Задамо змінну

$ STRING=aabbcc $ echo $(STRING) aabbcc Для видалення символів на початку рядка використовуємо команди: $ echo $(STRING#?) abbcc $ echo $(STRING#???) bcc для видалення символів наприкінці рядка: $ echo $ (STRING%?) aabbc $ echo $(STRING%???) aab Що б запам'ятати, коли застосовувати знак, а коли використовують ось такий оригінальний спосіб:
Символи розташовуються на клавіатурі послідовно та:
- зліва від, означає з початку рядка
- Праворуч, означає до кінця рядка

2. Видалення регулярних виразів на початку або наприкінці рядка

Регулярні вирази (regular expressions або RegExp, regex) - це рядок-шаблоном або "маска", що задає правило пошуку.

Знову поставимо змінну

$ STRING=GNULinux $ echo $(STRING) GNULinux видаляємо регулярний вираз на початку рядка: $ echo $(STRING#GNU) Linux видаляємо регулярний вираз у кінці рядка: $ echo $(STRING%Linux) GNU Тепер теж саме, але використовуючи « *» (астериск)
видаляємо регулярний вираз на початку рядка (): $ echo $(STRING#*U) Linux видаляємо регулярний вираз у кінці рядка (): $ echo $(STRING%L*) GNU

Використання регулярних виразівможе бути скомбіновано з "?" (Знаком будь-якого символу) ():

$ echo $(STRING%??n*) GNU

3. Використання здвоєних ## і %%

Якщо при видаленні з рядка регулярних виразів(*regex або regex*), при використанні "#" і "%" з "*" - видалення йде до першого входження регулярного вираження, то при використанні здвоєних "##" і "%%" - до останнього:

І знову поставимо змінну

$STRING=abcdcba $echo $(STRING) abcdcba STRING=abcdcba $(STRING#*c) dcba$(STRING##*c) ba$(STRING%c*) abcd$(STRING%%c*) ab$ echo $(STRING#*c) dcba $ echo $(STRING##*c) ba $ echo $(STRING%c*) abcd $ echo $(STRING%%c*) ab

4.

Шпаргалка по sed

Пошук та заміна

Заміна першого входження

Глобальна заміна

$STRING="abracadabra" $echo "$(STRING/a/O)" Obracadabra $echo "$(STRING//a/O)" ObrOcOdObrO $echo "$(STRING/#a/O)" Obracadabra $echo " $(STRING/%a/O)» abracadabrO $ echo «$(STRING/a/)» bracadabra $ echo «$(STRING//a/)» brcdbr

5. Вилучення підрядка використовуючи зміщення та довжину

Зміщення від краю рядка

Довжина підрядки

5.1 Зміщення за позитивних значень

При позитивних значеннях усунення першому символу рядка відповідає значення "".

Приклади з позитивними значеннями: $STRING="Debian Gentoo RedHat" $echo $(STRING:0:6) Debian $echo $(STRING:14) RedHat $echo $(STRING:7:6) Gentoo
5.2 Зміщення за негативних значень

При негативних значеннях відлік ведеться з кінця рядка, а останньому символу рядка відповідає значення, що дорівнює «».

Для запису негативного зміщення між двокрапкою та знаком мінус потрібно залишати прогалину або брати негативне значення у круглі дужки.

Якщо не задана, то довжина підрядка автоматично продовжується до кінця.

Приклади з негативними значеннями: $ STRING="Debian Gentoo RedHat" $ echo $(STRING: -6) RedHat $ echo $(STRING:(-6)) echo $(STRING:(-6):10) # довжина перевищує зсув RedHat
5.3 Негативні значення.

Якщо приймає негативне значення, вона працює як зміщення від кінця рядка. Результатом буде підрядок між першим та другим зсувами:

$ STRING="Debian Gentoo RedHat" $ echo $(STRING:7:-7) Gentoo $ echo $(STRING:(-14):-7) Gentoo

Як все це застосувати на практиці:

Нижче представлені різні варіанти коду для зміни розширення при пакетному перекодуванні аудіо файлів: for i in *.wav; do lame "$i" "$(i%???)mp3"; done; for i in *.wav; do lame "$i" "$(i%wav)mp3"; done; for i in *.wav; do lame "$i" "$(i%.*).mp3"; done; for i in *.wav; do lame "$i" "$(i/wav/mp3)"; done; for i in *.wav; do lame "$i" "$(i:0:-3)mp3"; done;

6. Підрахунок кількості символів у рядку

$STRING="Підрахунок кількості символів у рядку" $ echo $(#STRING) 36
Дізнатись кількість символів у файлі: $ ARRAY=(`cat file.html`) $ echo $(#ARRAY[@]) 1158

Тут слід зазначити, що файл читається не просто змінну, а масив, оскільки він складається з кількох рядків. Тому для правильного підрахунку потрібно ставити. Якщо цього не зробити, то команда прочитає лише перший рядок із файлу:

$ ARRAY=(`cat file.html`) $ echo $(#ARRAY) 7 І справді, перший рядок містить лише тег і символ перекладу рядка віндовс () - і того 7 символів.

7. Зміна регістру символів

Перекладає перший символ у верхній регістр

Перекладає всі символи у верхній регістр

Переводить перший символ у нижній регістр

Перекладає всі символи в нижній регістр

Інвертує регістр першого символу

Інвертує регістр усіх символів

Теги: Linux, bash, shell, regular expressions, parameter expansions, RegExp, regex, length, offset, for, in, do. lame, done, *.wav, mp3, CR+LF, регулярні вирази, шаблон, пошук, змінна, масив, рядок, символи, верхній, нижній, регістр

Вступ

Команда sed – це редактор потоку даних (Stream EDitor) для автоматичного редагування текстів. "Редактор потоку" - у тому сенсі, що може редагувати вхідний потік даних безперервно, скажімо, у складі програмного каналу (pipe). Автоматично - це означає, що, як тільки ви поставите правила редагування, подальше відбувається без вашої стомливої ​​участі. Іншими словами, редактор sed не є інтерактивним.

Програма sed складніша, ніж ті команди, які ми вже встигли розглянути у попередніх статтях циклу HuMan. У її складі арсенал власних команд, тому, щоб уникнути тавтології та плутанини, у цій статті команда sed надалі іменуватиметься "програмою" або "редактором", а команди редактора sed - просто командами.

Програма sed здатна виконувати складні завдання і потрібно витратити час, щоб навчитися ці завдання формулювати.

Але поряд зі складними діями, у команди sed є прості, але дуже корисні можливості, освоїти які не важче, ніж інші команди Юнікс. Не дозволяйте собі через складність освоєння усієї програми, відмовлятися від її простих аспектів.

Ми почнемо від простого до складного, тому ви завжди зможете зрозуміти, де слід зупинитися.

Команда s - substitution (заміна)

Програма sed має багато власних команд. Більшість користувачів знають тільки команду s, і це цілком вистачає, щоб працювати з редактором sed. Команда s замінює ЗРАЗОК на ЗАМІНУ:

sed s/ЗРАЗОК/ЗАМІНА/

$ echo день | sed s/день/ніч/ (Enter) ніч

Простіше не буває. А ось приклад із введенням із файлу zar.txt:

Вранці він робив зарядку.

Блискавка – електричний заряд.

$ sed s/заряд/разряд/ zar.txt Вранці він робив розрядку.

Блискавка – електричний розряд.

Прямий слеш (/) використовується як роздільник за традицією, так як предок програми sed - редактор ed використовує їх (як і редактор vi). У деяких випадках такий роздільник дуже незручний, наприклад, коли треба змінювати шляхи (path) до директорій, які також містять прямий слеш (/usr/local/bin). І тут доводиться розділяти прямі слеши зворотними:

Sed "s/\/usr\/local\/bin/\/common\/bin/"

Це називається "частокол" і виглядає дуже потворно, а головне, незрозуміло.

Унікальність програми sed у тому, що вона дозволяє використовувати будь-який роздільник, наприклад знак підкреслення:

$ echo день | sed s_день_ніч_ніч

або двокрапка:

$ echo день | sed s:день:ніч: ніч

Якщо в пошуках роздільника, який вам подобається, ви отримуєте повідомлення "незавершена команда `s"", значить цей символ не підходить як роздільник, або ви просто забули поставити один-два роздільники.

У цій статті я змушений використовувати традиційний роздільник (/) щоб не збивати читача з пантелику, але в разі необхідності стану використовувати як роздільник тільду (~).

Регулярні вирази (РВ)

(Regular expressions, regexp, RE)

Тема регулярних виразів настільки велика, що їй присвячені цілі книги (дивись посилання наприкінці статті). Тим не менш, говорити всерйоз про редактор sed, не застосовуючи регулярних виразів, також непродуктивно, як говорити про тригонометрію за допомогою лічильних паличок. Тому необхідно розповісти хоча б про ті регулярні висловлювання, які часто використовуються з програмою sed.

зАбо будь-яка інша літера. Більшість літер, цифр та інших неспеціальних символів вважаються регулярними виразами, які представляють себе.

* Астериск, який слідує за будь-яким символом або регулярним виразом, означає будь-яке число (у тому числі нульове) повторів цього символу або регулярного виразу.

\+ Означає один або більше повторів символу або регулярного виразу.

\? Означає жодного чи повторення.

\(i\)Значить рівно і повторів.

\(i,j\)Число повторів знаходиться в інтервалі від i до j включно.

\(i,\)Число повторів більше або дорівнює i.

\(,j\)) Число повторів менше або дорівнює j.

\(RE\)) Запам'ятати регулярне вираз або його частину з метою подальшого використання як єдине ціле. Наприклад, \(а-я\)* шукатиме будь-яке поєднання будь-якої кількості (у тому числі і нульового) малих літер.

. Це означає будь-який символ, у тому числі символ нового рядка.

^ Означає нульовий вираз початку рядка. Інакше кажучи, те, що стоїть цей знак, має з'являтися на початку рядка. Наприклад, ^#include шукатиме рядки, що починаються з #include.

$ Те саме, що й попереднє, тільки стосується кінця рядка.

[ПЕРЕЛІК]Означає будь-який символ зі списку. Наприклад, шукатиме будь-яку англійську голосну букву.

[^СПИСОК]Означає будь-який символ, крім тих, що у списку. Наприклад, [^aeiou] шукатиме будь-яку приголосну. Примітка: СПИСОК може бути інтервалом, наприклад [а-я], що означатиме будь-яку літеру. Якщо потрібно включити в СПИСОК ] (квадратну дужку), вкажіть її у списку першої; якщо потрібно включити в СПИСОК (дефіс), то вкажіть його в списку першим або останнім.

RE1\|RE2Означає РВ1 чи РВ2.

RE1RE2означає об'єднання регулярних виразів РВ1 і РВ2.

\nОзначає новий рядок.

\$; \*; \.; \[; \\; \^ Означають відповідно: $; *; .; [; \; ^

Увага: Інші умовні позначення на основі зворотного слеша (\), прийняті в мові С, не підтримуються програмою sed.

\1 \2 \3 \4 \5 \6 \7 \8 \9 Означає відповідну за рахунком частину регулярного виразу, запам'ятана за допомогою знаків (і).

Декілька прикладів:

abcdefозначає abcdef

a*bОзначає нуль або будь-яку кількість букв а та одна буква b. Наприклад, aaaaaab; ab; або b.

a?bозначає b або ab

a+b\+Означає одну або більше літер і одну або більше літер b. Наприклад: ab; aaaab; abbbbb; або aaaaaabbbbbbbbb.

.* Означає всі символи на рядку на всіх рядках, включаючи порожні.

.\+ Означає всі символи на рядку, але тільки на рядках, що містять хоча б один символ. Порожні рядки не відповідають цьому регулярному виразу.

^main.*(.*)Буде шукати рядки, що починаються зі слова main, а також мають у своєму складі відчиняючу та закриваючу дужки, причому перед і після дужки, що відкриває, може знаходитися будь-яка кількість символів (а може і не знаходитися).

^# Шукатиме рядки, що починаються зі знака # (наприклад коментарі).

\\$ Шукатиме рядки, що закінчуються зворотним слешем (\).

Будь-які літери чи цифри

[^ ]\+ (У квадратній дужці, крім символу ^, міститься ще пробіл і табуляція) - означає один або будь-яку кількість будь-яких символів, крім пробілу та табуляції. Зазвичай мається на увазі слово.

^.*A.*$Означає велику букву А точно в середині рядка.

A. \ (9 \) $Означає велику букву А, точно десяту за рахунком від кінця рядка.

^.\(,15\)AОзначає велику букву А, точно шістнадцяту за рахунком від початку рядка.

Тепер, коли ми познайомилися з деякими регулярними виразами, повернемося до команди редактора sed.

Використання символу & коли зразок невідомий "Як це невідомий?", - Запитайте ви - "Ти хіба не знаєш, що хочеш замінити?" Відповім: я хочу взяти в дужки будь-які цифри, знайдені у тексті. Як це зробити? Відповідь: застосувати символ &.

Символ & (амперсанд), будучи поміщений до складу ЗАМІНИ, означає будь-який знайдений у тексті ЗРАЗОК. Наприклад:

$ echo 1234 | sed "s/*/(&)/" (1234)

Зірочка (астериск) після інтервалу потрібна, щоб замінені були всі цифри, що зустрілися у зразку. Без неї вийшло б:

$ echo 1234 | sed "s//(&)/" (1)234

Тобто як зразок взято першу ж знайдену цифру.

Ось приклад із цілком осмисленим навантаженням: складемо файл formula.txt:

A+432-10=n

і застосуємо до нього команду:

$ sed "s/*-*/(&)/" formula.txt a+(432-10)=n

Математична формула набула однозначного змісту.

Ще символ амперсанда можна використовувати для подвоєння зразка:

$ echo 123 | sed "s/*/& &/" 123 123

Тут є одна тонкість. Якщо ми трохи ускладнимо приклад:

$ echo "123 abc" | sed "s/*/& &/" 123 123 abc

як і слід було очікувати, подвоюються лише цифри, оскільки в ЗРАЗКУ немає букв. Але якщо ми змінимо частини тексту місцями:

$ echo "abc 123" | sed "s/*/& &/" abc 123

то жодного подвоєння цифр не вийде. Це особливість регулярного виразу * - воно шукає відповідності лише першому символі рядка. Якщо ми хочемо подвоєння цифр, де б вони не знаходилися, потрібно доопрацювати регулярний вираз у ЗАМІНІ:

$ echo "abc defg 123" | sed "s/*/& &/" abc defg 123 123

тоді цифри подвоюватимуться, незалежно від кількості попередніх "слів".

Використання умовних знаків \(, \) та \1 для обробки частини ЗРАЗКУ Умовні знаки \(і \) (escaped parentheses) застосовуються для запам'ятовування частини регулярного виразу.

Умовний знак \1 означає першу запам'ятову частину, \2 - другу, і так далі, аж до дев'яти запам'ятаних частин (більше програма не підтримує). Розберемо приклад:

$ echo abcd123 | sed "s/\(*\).*/\1/" abcd

Тут \(*\) означає, що програма має запам'ятати всі буквені символи у будь-якій кількості; .* означає будь-яку кількість символів після першої пам'ятої частини; а \1 означає, що хочемо бачити лише першу запам'ятову частину. Так і є: у виведенні програми ми бачимо лише літери та жодних цифр.

Для того, щоб поміняти слова місцями, потрібно запам'ятати два суб-зразки, а потім поміняти їх місцями:

$ echo дурний пінгвін | sed "s/\([а-я]*\) \([а-я]*\)/\2 \1/" пінгвін дурний

Тут 2 означає другий суб-ЗРАЗОК, а 1 -перший. Зверніть увагу на інтервал між першим виразом \([а-я]*\) та другим виразом \([а-я]*\). Він необхідний, щоб було знайдено два слова.

Знак \1 зовсім не повинен бути тільки в ЗАМІНІ, він може бути присутнім також і в ЗРАЗЦІ, наприклад, коли ми хочемо видалити дублікати слів:

$ echo пінгвін пінгвін | sed "s/\([а-я]*\) \1/\1/" пінгвін

Модифікатори заміни команди s

Модифікатори заміни встановлюються після останнього роздільника. Ці модифікатори визначають дії програми у разі, якщо в рядку знайшлося більше одного збігу з ЗРАЗКОМ, і яким чином проводити заміну.

Модифікатор / g

Глобальна заміна (Global replacement)

Програма sed, як і більшість утиліт Юнікс, під час роботи з файлами зчитують по одному рядку. Якщо ми наказуємо замінити слово, програма замінить лише перше слово, що збіглося з ЗРАЗКОМ, на даному рядку. Якщо ми хочемо змінити кожне слово, що збіглося зі зразком, слід ввести модифікатор /g.

Без модифікатора /g:

$ echo кіт цей, був звичайнісінький кіт | sed "s/кіт/кошеня/" кошеня це, був звичайнісінький кіт

Редактор замінив тільки перше слово, що збіглося.

А тепер із модифікатором глобальної заміни:

$ echo кіт цей, був звичайнісінький кіт | sed "s/кіт/кошеня/g" кошеня це, було найзвичайніше кошеня

Усі збіги у цьому рядку було замінено.

А якщо потрібно змінити всі слова, скажімо взяти їх у дужки? Тоді на допомогу знову прийдуть регулярні вирази. Щоб вибрати всі буквені символи, як верхнього, так і нижнього регістру, можна скористатися конструкцією [А-Яа-я], але в неї не потраплять такі слова як "щось" або "з" їзд. Набагато зручніше конструкція [^ ]*, яка відповідає всім символам, крім пробілу.

$ echo дурний пінгвін несміливо ховає | sed "s/[^ ]*/(&)/g" (дурний) (пінгвін) (несміливо) (ховає)

Як вибрати потрібний збіг з кількох

Якщо не застосовувати модифікаторів, то програма sed замінить тільки перше слово, що збіглося з Зразком. Якщо застосувати модифікатор /g, то програма замінить кожне слово, що збіглося. А як можна вибрати один із збігів, якщо їх кілька на рядку? - За допомогою вже знайомих нам умовних знаків \(і \) запам'ятати суб-ЗРАЗКИ та вибрати потрібний за допомогою знаків \1 - \9.

$ echo дурний пінгвін | sed "s/\([а-я]*\) \([а-я]*\)/\2 /" пінгвін

У цьому прикладі ми запам'ятали обидва слова, і, поставивши друге (пінгвін) на перше місце, перше (дурний) видалили, поставивши в секції ЗАМІНИ замість нього прогалину. Якщо ми поставимо замість пробілу якесь слово, воно замінить перше (дурний):

$ echo дурний пінгвін | sed "s/\([а-я]*\) \([а-я]*\)/\2 розумний /" пінгвін розумний

Числовий модифікатор

Це одне/двох/трьох -значне число, яке ставиться після останнього роздільника і вказує, яке збіг підлягає заміні.

$ echo дуже дурний пінгвін | sed "s/[а-я]*/хороший/2" дуже гарний пінгвін

У цьому прикладі кожне слово є збігом, і ми вказали редактору, яке слово ми хочемо замінити, поставивши модифікатор 2 після секції ЗАМІНИ.

Можна комбінувати цифровий модифікатор із модифікатором /g. Якщо потрібно залишити незмінним перше слово, а друге та наступні замінити на слово "(видалено)", то команда буде така:

$ echo дуже дурний пінгвін | sed "s/[а-я]*/(видалено)/2g" дуже (видалено) (видалено)

Якщо потрібно дійсно видалити всі наступні збіги, крім першого, то в секції ЗАМІНИ слід поставити пробіл:

$ echo дуже дурний пінгвін | sed "s/[а-я]*/ /2g" дуже

Або зовсім нічого не ставити:

$ echo дуже дурний пінгвін | sed "s/[^ ]*//2g" дуже

Числовий модифікатор може бути будь-яким цілим числом від 1 до 512. Наприклад, якщо потрібно поставити двокрапку після 80 символів кожного рядка, то допоможе команда:

$ sed "s/./&:/80" ім'я_файлу

Модифікатор /p – видавати на стандартний вихід (друк – print)

Програма sed і так за промовчанням видає результат на стандартний вихід (наприклад, екран монітора). Цей модифікатор застосовується тільки з опцією sed -n, яка блокує виведення результату на екран.

Модифікатор /w

Дозволяє записувати результати обробки тексту у вказаний файл:

$ sed "s/ЗРАЗОК/ЗАМІНА/w ім'я_файлу

Модифікатор /e (розширення GNU)

Дозволяє вказати команду шелла (не програми sed) як ЗАМІНИ. Якщо відповідність ЗРАЗКУ буде знайдена, то вона буде замінена на виведення вказаної в секції ЗАМІНИ команди. Приклад:

$ echo ніч | sed "s/ніч/echo день/e" день

Модифікатори /I та /i (розширення GNU)

Роблять процес заміни нечутливим до регістру символів.

$ echo Night | sed "s/night/day/i" day

Комбінації модифікаторів

Модифікатори можна комбінувати, коли це має сенс. У цьому слід ставити модифікатор w останнім.

Умовні позначення (розширення GNU) Їх всього п'ять:

\Lпереводить символи ЗАМІНИ в нижній регістр \lпереводить наступний символ ЗАМІНИ в нижній регістр \Uпереводить символи ЗАМІНИ у верхній регістр \uпереводить наступний символ ЗАМІНИ у верхній регістр \Eскасовує переклад, розпочатий \L або \U З очевидних причин ці умовні позначення застосовуються поодинці. Наприклад:

$ echo дурний пінгвін | sed "s/дурний/\u&/" Дурний пінгвін

$ echo маленьке цуценя | sed "s/[а-я]*/\u&/2" маленьке Цуценя

Ми розглянули майже всі аспекти команди s редактора sed. Тепер настала черга розглянути опції цієї програми.

Опції програми sed

Програма має напрочуд мало опцій. (Що дещо компенсує надлишок команд, модифікаторів та інших функцій). Крім загальновідомих опцій --help (-h) і --version (-V), які ми розглядати не будемо, їх лише три:

Опція -e--expression=набір_команд

Один із способів виконання кількох команд – застосування опції -e. Наприклад:

Sed -e "s/a/A/" -e "s/b/B/" ім'я_файлу

Усі попередні приклади у цій статті не вимагали застосування опції -e лише тому, що містили одну команду. Ми могли поставити в прикладах опцію -e, це б нічого не змінило.

Опція -fЯкщо потрібно виконати велику кількість команд, зручніше записати їх у файл і застосувати опцію -f:

Sed -f sedscript ім'я файлу

Sedscript тут - ім'я файлу, що містить команди. Цей файл називається скриптом програми sed (далі просто скрипт). Кожна команда скрипта має займати окремий рядок. Наприклад:

# коментар - Цей скрипт змінить всі малі голосні літери на великі s/a/A/g s/e/E/g s/i/I/g s/o/O/g s/u/U/g

Назвати скрипт можна як завгодно, важливо не плутати файл скрипта з файлом, що обробляється.

Опція -nПрограма sed -n нічого не виводить на стандартний вихід. Щоб отримати висновок, потрібна спеціальна вказівка. Ми вже познайомилися з модифікатором /p, за допомогою якого можна надати таку вказівку. Згадаймо файл zar.txt:

$ sed "s/1-9/&/p" zar.txt Вранці він робив зарядку.

Блискавка – електричний заряд.

Так як збігів з ЗРАЗКОМ не знайдено (у файлі немає цифр), то команда s з модифікатором /p і знаком & як ЗАМІНИ (нагадаю, що амперсанд означає сам ЗРАЗОК), працює як команда cat.

Якщо зразок буде знайдено у файлі, то рядки, що містять зразок, будуть подвоєні:

$ sed "s/зарядку/&/p" zar.txt Вранці він робив зарядку.

Вранці він робив зарядку.

Блискавка – електричний заряд.

Тепер додамо опцію -n:

Використовуючи лише одну команду s, ми переконалися у надзвичайно широких можливостях редактора sed. Адже все, що він робить, зводиться до пошуку та заміни. Причому в процесі роботи sed редагує кожен рядок поодинці, не звертаючи уваги на інші. Було б зручно обмежити коло рядків, що підлягають зміні, наприклад:

  • Вибирати рядки за номерами
  • Вибирати рядки у певному діапазоні номерів
  • Вибирати тільки рядки, які містять певний вираз
  • Вибирати лише рядки між деякими виразами
  • Вибирати лише рядки від початку файлу і до деякого виразу
  • Вибирати лише рядки від деякого виразу і до кінця файлу

Програма sed вміє все це і більше. Будь-яка команда редактора sed може застосовуватися адресно, у певному діапазоні адрес, або з переліченими вище обмеженнями кола рядків. Адреса або обмеження повинні безпосередньо передувати команді:

Sed "адреса/обмеження команда"

Вибір рядків за номерами

Це найпростіший випадок. Просто вказуємо номер потрібного рядка перед командою:

$ sed "4 s/[а-я]*//i" gumilev.txt Яка дивна млість У ранніх сутінках ранку, У таненні весняного снігу, усім, що гине і мудро.

$ sed "3 s/В/(В)/" gumilev.txt Яка дивна млість У ранніх сутінках ранку, (В) танення весняного снігу, У всьому, що гине і мудро.

Вибір рядків у діапазоні номерів

Діапазон вказується, як не дивно, через кому:

$ sed "2,3 s/В/(В)/" gumilev.txt Яка дивна млість (В) ранніх сутінках ранку, (В) танення весняного снігу, У всьому, що гине і мудро.

Якщо потрібно вказати діапазон до останнього рядка файлу, а ви не знаєте скільки в ньому рядків, то скористайтеся знаком $:

$ sed "2,$ s/в/(в)/i" gumilev.txt Яка дивна млість (в) ранніх сутінках ранку, (в) танення весняного снігу, (в) про все, що гине і мудро.

Вибір рядків, що містять певний вираз

Вираз, що шукається, полягає в прямі слеші (/) і ставиться перед командою:

Яка дивна млість (в) ранніх сутінках ранку, У таненні весняного снігу, У всьому, що гине і мудро.

Вибір рядків у діапазоні між двома виразами

Також як і у випадку з номерами рядків, діапазон задається через кому:

Яка дивна млість (в) ранніх сутінках ранку, (в) танення весняного снігу, (в) про все, що гине і мудро. .

Вибір рядків від початку файлу і до якогось виразу

Яка дивна млість (в) ранніх сутінках ранку, (в) танення весняного снігу, У всьому, що гине і мудро.

Вибір рядків від якогось виразу і до кінця файлу

$ sed "/снігу/,$ s/в/(в)/i" gumilev.txt Яка дивна млість У ранніх сутінках ранку, (в) таненні весняного снігу, (в)про все, що гине і мудро.

Інші команди редактора sed

Команда d (delete)

Видаляє із стандартного виводу зазначені рядки:

$ sed "2 d" gumilev.txt Яка дивна млість У таненні весняного снігу, У всьому, що гине і мудро.

Причому частіше пишуть простіше (без пропуску):

Sed "2d" gumilev.txt

Все, що було сказано в попередньому розділі про адресацію рядків, справедливе і для команди d (як і для багатьох команд редактора sed).

За допомогою команди d зручно викинути непотрібну "шапку" якогось поштового повідомлення:

$ sed "1,/^$/ d" ім'я_файлу

(Видалити рядки з першого і до першого порожнього рядка).

Позбудеться коментарів у конфігураційному файлі:

$ sed "/^#/ d" /boot/grub/menu.lst

І мало, де потрібно видалити зайві рядки!

Команда p (print)

Англійське слово "print" перекладається як "друкувати", що в російській асоціюється з принтером, або, принаймні, з клавіатурою. Насправді слово це в англійському контексті часто означає просто виведення на екран монітора. Тому команда p нічого не друкує, а просто виводить на екран вказані рядки.

Будучи застосованою сама собою, команда p подвоює рядки у виведенні (адже програма sed за замовчуванням виводить рядок на екран, а команда p виводить той самий рядок вдруге).

$ echo у мене є кіт | sed "p" у мене є кіт у мене є кіт

Цією властивістю є застосування, наприклад подвоїти порожні рядки для поліпшення вигляду тексту:

$ sed "/^$/ p ім'я_файлу

Але справжнє своє обличчя команда p розкриває разом із опцією -n, яка, як пам'ятаєте, забороняє виведення рядків на екран. Комбінуючи опцію -n з командою p, можна одержати у виведенні лише потрібні рядки.

Наприклад, переглянути рядки з першого до десятого:

$ sed -n "1,10 p" имя_файла

Або тільки коментарі:

$ sed -n "/^#/ p" /boot/grub/menu.lst # GRUB configuration file "/boot/grub/menu.lst".

Що дуже нагадує роботу програми grep, із чим ми вже зіштовхувалися, коли говорили про опцію -n з модифікатором /p. Але, на відміну від команди grep, редактор sed дає можливість не тільки знайти ці рядки, а й змінити їх, замінивши, наприклад, скрізь Linux на Unix:

$ sed -n "/^#/p" /boot/grub/menu.lst | sed "s/Linux/Unix/" # GRUB configuration file "/boot/grub/menu.lst".

# generated by "grubconfig". Нд 23 Бер 2008 21:45:41 # # Start GRUB Global section # End GRUB Global Section # Unix bootable partition config begins # Unix bootable partition config ends # Unix bootable partition config begins # Unix bootable partition config ends

Команда!

Іноді потрібно редагувати всі рядки, крім тих, що відповідають ЗРАЗКУ, або вибору. Символ знака оклику (!) інвертує вибір. Наприклад, видалимо всі рядки, крім другого з чотиривірша Гумільова:

$ sed "2 !d" gumilev.txt У ранніх сутінках ранку,

Або виберемо всі рядки, крім коментарів, із файлу /boot/grub/menu.lst:

$ sed -n "/^#/ !p" /boot/grub/menu.lst default 1 timeout 20 gfxmenu (hd0,3)/boot/message title SuSe on (/dev/hda3) root (hd0,2) kernel /boot/vmlinuz root=/dev/hda3 ro vga=773 acpi=off title Linux on (/dev/hda4) root (hd0,3) kernel /boot/vmlinuz root=/dev/hda4 ro vga=0x317

Команда q (quit)

Команда q припиняє роботу програми sed після вказаного рядка. Це зручно, якщо потрібно припинити редагування після досягнення певного місця у тексті:

$ sed "11 q" имя_файла

Ця команда закінчить роботу з досягнення 11-го рядка.

Команда q - одна з небагатьох команд sed, які не приймають діапазонів рядків. Не може команда припинити роботу 10 разів поспіль, якщо ми введемо:

Sed "1,10 q" Абсурд!

Команда w (write)

Подібно до модифікатора w команди s, ця команда дозволяє записати виведення програми у файл:

$ sed -n "3,$ w gum.txt" gumilev.txt

Ми отримаємо файл gum.txt, який містить два останні рядки чотиривірші Гумільова з файлу gumilev.txt. Причому якщо такий файл вже існує, то буде перезаписаний. Якщо не ввести опцію -n, то програма, окрім створення файлу gum.txt, ще й виведе на екран весь зміст файлу gumilev.txt.

Для роботи в командному рядку зручніше користуватися звичайним перенаправленням виводу (> або >>), але в sed скриптах, ймовірно, команда w знайде своє застосування.

Ця команда не тільки прочитає вказаний файл, але й вставить його вміст у потрібне місце файлу, що редагується. Для вибору "потрібного місця" використовується вже знайома нам адресація (за номерами рядків, за виразами та ін.). Приклад:

$ echo З вірша Гумільова: | sed "r gumilev.txt"

З вірша Гумільова:

Яка дивна млість У ранніх сутінках ранку, У таненні весняного снігу, У всьому, що гине і мудро.

Команда =

Видасть номер зазначеного рядка:

$ sed "/снігу/=" gumilev.txt Яка дивна млість У ранніх сутінках ранку, 3 У таненні весняного снігу, У всьому, що гине і мудро.

$ sed -n "/снігу/=" gumilev.txt 3

Команда приймає лише одну адресу, не приймає інтервалів.

Команда y

Ця команда замінює символи з секції ЗРАЗОК символами секції ЗАМІНА, працюючи як програма tr.

$ echo Автомобіль - спадщина минулого | sed "y/Авто/Паро/" Паромобіль - спадщина минулого

Команда yпрацює тільки якщо кількість символів в ЗРАЗКУ дорівнює кількості символів у ЗАМІНІ.

Скрипти програми sed

Щоб користуватися редактором sed як повноцінним текстовим редактором, необхідно освоїти складання скриптів sed. Програма sed має власну нескладну мову програмування, що дозволяє складати скрипти, здатні творити чудеса.

Ця стаття не може вмістити описи скриптів sed, як і її автор не ставить собі за мету освоєння мови програмування sed. У цій статті я наголошував на використанні редактора sed у командному рядку, маючи приціл на використання його як фільтр у програмних каналах (pipes). З цієї причини я опустив численні команди sed, що застосовуються лише у його скриптах.

Існує безліч любителів редактора sed, та безліч статей на тему скриптописання, у тому числі й у Рунеті. Так що для тих, хто зацікавився цією чудовою програмою, не важко поповнити свої знання.

Програма sed та символи кирилиці

Як видно з прикладів у цій статті, програма sed на правильно русифікованій системі вільно володіє "великою та могутньою" мовою.

Резюме програми sed

Програма sed - це багатофункціональний редактор потоку даних, незамінний для:

  • Редагування великих текстових масивів
  • Редагування файлів будь-якої величини, коли послідовність дій, що редагують, надто складна
  • Редагування даних у міру їх надходження, у тому числі в режимі реального часу, тобто у випадках, коли важко або зовсім неможливо використовувати інтерактивні текстові редактори.

Для освоєння програми sed в повному обсязі будуть потрібні тижні або навіть місяці роботи, тому що для цього необхідно:

  • Вивчити регулярні вирази
  • Навчитися писати скрипти sed, освоївши нескладну мову програмування, що застосовується в цих скриптах

З іншого боку, освоїти кілька найбільш уживаних команд редактора sed не складніше, ніж будь-яку команду Юнікс; сподіваюся, ця стаття допоможе вам у цьому.

Післямова

До цих пір, у статтях циклу HuMan, я прагнув хоча б коротко розкрити кожну опцію, кожен параметр команди, що описується, так щоб стаття могла замінити мани. Надалі я продовжуватиму дотримуватися цього принципу.

Ця стаття є винятком, оскільки не визначає всіх можливостей програми. Для повного їхнього опису знадобилася б не стаття, а книга. Тим не менш, стаття дозволяє отримати уявлення про редактор sed і почати працювати з цією дивовижною програмою, використовуючи найвживаніші її команди.

Редактор потоків sed – це неінтерактивний текстовий редактор, який виконує операції на даних, що надходять зі стандартного введення або файлу. Sed редагує інформацію рядково.

Були описані основи роботи з редактором sed. Даний посібник охоплює більш просунуті прийоми.

Об'єднання команд

Іноді виникає необхідність передати редактору sed кілька команд одночасно. Це робиться кількома способами.

Якщо у вас ще немає тестового файлу для роботи з sed, створіть таке оточення:

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .
echo "this is the song that never ends


not knowing what it was

just because..." > annoying.txt

Оскільки sed працює зі стандартним введенням та виведенням, можна, звичайно, просто викликати різні команди sed разом в одному рядку:

sed "s/and/\&/" annoying.txt | sed "s/people/horses/"

yes, it goes on & on, my friend
some horses started singing it
not knowing what it was
& they"ll continue singing it forever
just because...

Такий метод спрацює, але кілька викликів sed створюють зайве навантаження, займають більше місця і не використовують вбудовані можливості sed.

Передати sed декілька команд одночасно можна за допомогою опції -e, яку потрібно вставити перед кожною командою:

sed -e "s/and/\&/" -e "s/people/horses/" annoying.txt

Також можна об'єднати команди в рядок за допомогою символу крапки з комою. Цей метод працює так само як і попередній.

sed "s/and/\&/;s/people/horses/" annoying.txt

Зверніть увагу: при використанні прапора –e виникає необхідність розривати одиночні лапки, а при використанні точки з комою всі команди можна перерахувати в одних лапках.

Ці два способи одночасного виклику кількох команд досить зручні, проте трапляються випадки, коли потрібно використовувати простий рядок команд.

Також слід ознайомитись з оператором =. Цей оператор вставляє номер рядка між кожним існуючим рядком. Результат виглядає так:

sed "=" annoying.txt
1
this is the song that never ends
2
yes, it goes on and on, my friend
3
some people started singing it
4
not knowing what it was
5
and they"ll continue singing it forever
6
just because...

Тепер спробуйте відредагувати текст, щоб зрозуміти, як змінюється формат нумерації.

G за замовчуванням додає порожній рядок між вже існуючими рядками.

sed "G" annoying.txt
_
this is the song that never ends
_
yes, it goes on and on, my friend
_
some people started singing it
_
not knowing what it was
_
and they"ll continue singing it forever
_
just because...

Спробуйте скомбінувати ці дві команди. Спочатку може здатися, що виведення цих команд міститиме порожній рядок між рядком тексту та рядком з номером. Однак висновок виглядає так:

sed "=; G" annoying.txt
1
this is the song that never ends
_
2
yes, it goes on and on, my friend
_
3
some people started singing it
_
4
not knowing what it was
. . .
. . .

Це тому, що оператор = змінює потік виведення (це означає, що використовувати отриманий висновок для подальшого редагування не можна).

Це можна обійти за допомогою двох дзвінків sed, де перший дзвінок сприйматиметься як простий потік тексту для другого.

sed "=" annoying.txt | sed "G"
1
_
this is the song that never ends
_
2
_
yes, it goes on and on, my friend
_
3
_
some people started singing it
. . .
. . .

Майте на увазі, деякі з команд працюють аналогічно, особливо якщо ви об'єднуєте кілька команд і висновок відрізняється від очікуваного.

Просунута адресація

Однією з переваг команд sed, що підтримують адресацію, є те, що вони можуть використовувати регулярні вирази як критерії. Це означає, що можна працювати з файлами, вміст яких точно не відомий.

sed "1,3s/.*/Hello/" annoying.txt
Hello
Hello
Hello
not knowing what it was
and they"ll continue singing it forever
just because...

Натомість можна використовувати регулярний вираз, що містить лише рядки, що містять певний шаблон. Для цього потрібно розмістити шаблон пошуку між двома слішами (/) перед командою.

sed "/singing/s/it/& loudly/" annoying.txt
this is the song that never ends
yes, it goes on and on, my friend
some people started singing it loudly
not knowing what it was
and they"ll continue singing it loudly forever
just because...

У цьому прикладі слово loudly міститься перед першим it у кожному рядку, що містить слово singing. Зверніть увагу: другий і четвертий рядки залишилися без змін, оскільки вони не відповідають шаблону.

Вирази адресації можна ускладнити. Це робить команди гнучкішими.

Наступний приклад демонструє, як використовувати регулярні вирази для створення адрес для інших команд. Ця команда знаходить усі порожні рядки та видаляє їх:

sed "/^$/d" GPL-3
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
GNU General Public License є безкоштовно, copyleft license for
. . .
. . .

Майте на увазі, що регулярні вирази можуть бути використані у будь-якій частині діапазону.

Наприклад, можна видалити рядки між рядками START та END:

sed "/^START$/,/^END$/d" inputfile

Майте на увазі: ця команда видаляє всі рядки від першого знайденого слова START до першого знайденого слова END, і якщо вона знову зустріне слово START, вона продовжить видаляти дані.

Щоб інвертувати адресацію (тобто вибрати рядки, які не відповідають шаблону), використовуйте знак оклику (!).

Наприклад, щоб видалити будь-який заповнений рядок, потрібно ввести:

sed "/^$/!d" GPL-3

Адреса не обов'язково має бути складним виразом, щоб бути інвертованою. Інверсія так само працює зі звичайною нумерацією.

Використання додаткового буфера

Додатковий буфер (hold buffer) збільшує здатність sed виконувати багаторядкове редагування.

Додатковий буфер є область тимчасового зберігання, яка може бути змінена шляхом певних команд.

Наявність цього додаткового буфера дозволяє зберігати рядки під час роботи над іншими рядками.

Команди для роботи з буфером:

  • h: копіює поточний буфер обробки (останнього рядка, з якого ви працюєте) в додатковий буфер.
  • H: Додає поточний буфер обробки до кінця поточної додаткової обробки, розділяючи їх символом \n.
  • g: Копіює додатковий буфер у поточний буфер обробки. Попередній буфер обробки буде втрачено.
  • G: Додає поточний шаблон до поточного буфера обробки, розділяючи їх символом \n.
  • x: Підкачує поточний шаблон та додатковий буфер.

З вмістом додаткового буфера не можна працювати доти, доки він не переміщений у буфер обробки.

Розглянемо складний приклад.

Спробуйте з'єднати суміжні рядки за допомогою наступної команди:

sed -n "1~2h;2~2(H;g;s/\n/ /;p)" annoying.txt


Примітка: Насправді, для цього sed пропонує окрему вбудовану команду N; Однак для практики розглянути цей приклад корисно.

Опція –n пригнічує автоматичне виведення.

1~2h – визначення адреси, що виконує послідовну заміну кожного другого рядка тексту, починаючи з першого (тобто кожного непарного рядка). Команда h копіює рядки в додатковий буфер.

Решту команди взято у фігурні дужки. Це означає, що ця частина команди будуть успадковувати адресу, яка була щойно вказана. Без цих дужок, успадковувати адресу буде тільки команда H, а решта команд виконуватиметься для кожного рядка.

Звичайно, раніше згадана вбудована команда N значно коротша і простіша, і повертає такий же результат:

sed -n "N;s/\n/ /p" annoying.txt
this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they"ll continue singing it forever just because...

Скрипти sed

Команди можна компонувати у скрипти. Це дозволяє виконувати цілий набір команд на один цільовий шаблон.

Наприклад, можна написати скрипт, щоб створювати прості текстові повідомлення, які потрібно попередньо відформатувати.

Тоді вам не доведеться постійно повторювати ті самі команди для кожного повідомлення. Скрипт sed – це список команд, які потрібно застосувати на заданий об'єкт.

Наприклад:

s/this/that/g
s/snow/rain/g
1,5s/pinecone/apricot/g

Потім можна викликати файл:

sed -f sedScriptName fileToEdit

Висновок

Тепер ви знаєте більш просунуті методи роботи з sed.

Спершу команди sed складні для розуміння, в них легко заплутатися. Тому рекомендується поекспериментувати з ними, перш ніж використовувати їх на важливих даних.

Tags: ,