Sed, щоб результат не виводився в терміналі. Просунутий sed: керування текстовими потоками в Linux

Sed, щоб результат не виводився в терміналі. Просунутий sed: керування текстовими потоками в Linux

Документ створено: 16.02.2010

Ще приклад

For i in *.txt; do sed -i "/^\^/ s/^\^\([^\^]*\)\^\^/====\1====/;/^=/ s/$/ \n^ Команда ^ Опис ^/" $i; done

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

    /^\^/ s/^\^\([^\^]*\)\^\^/====\1====/ – якщо рядок починається з "^", замінити "^ Текст ^ ^ ". на "==== Текст ====";

    /^=/ s/$/ \n^ Команда ^ Опис ^/ - якщо рядок починається на " = " (а він починається, тому що в попередньому пункті ми самі це зробили, і тут умова тільки для того, щоб не чіпати інші рядки), замінити цей рядок на неї ж, плюс повернення каретки, плюс "^Команда^Опис^". Інакше кажучи, вставити після такого рядка рядок містить " ^ Команда ^ Опис ^ ".

Для чого це? Ось навіщо. Я розбив довгий dokuwiki файл з командами лінукс на дрібні файли. Вони вийшли виду:

^ Аналіз файлових систем^^ | badblocks -v /dev/hda1 | перевірити розділ hda1 на наявність bad-блоків ...

Ця послідовність команд перетворила їх на все:

Аналіз файлових систем ==== ^ Команда ^ Опис ^ | badblocks -v /dev/hda1 | перевірити розділ hda1 на наявність bad-блоків ...

Видалення рядка за контекстом

Для видалення рядка, що містить певний контекст, можна використовувати таку конструкцію:

Sed -i "/^AUTO_SAVE/d" notes.ini

Ця команда у файлі notes.ini видаляє всі рядки з AUTO_SAVE .

Видалення рядка або кількох рядків у файлі

Для видалення рядка або кількох рядків у файлі я використовую таку конструкцію:

Sed-i "2,1d"

Ця команда у файлі видаляє другий рядок.

Sed-i "5,10d"

Ця команда у файлі видалити десять рядків починаючи з п'ятої (включаючи п'яту).

Об'єднання рядків

Об'єднання двох сусідніх рядків попарно

Об'єднати попарно два рядки, розділені поверненням каретки:

Cat /etc/hosts | sed "N;s/\n/ - /"

PS. Розділювач: "-".

Переведення у верхній або нижній регістр

У верхній регістр:

Echo Sed | sed "s/.*/\U&/" SED

У нижній регістр:

Echo Sed | sed "s/.*/\L&/" sed

"Вирізати" шматок потоку

Наприклад візьмемо результат роботи dig:

$dig ya.ru

видасть нам

; <<>> DiG 9.7.0-P1<<>> ya.ru;; Global options: +cmd;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5252 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;ya.ru. IN A ;; ANSWER SECTION: ya.ru. 4194 IN A 87.250.251.3 ya.ru. 4194 IN A 93.158.134.3 ya.ru. 4194 IN A 213.180.204.3 ya.ru. 4194 IN A 77.88.21.3 ya.ru. 4194 IN A 87.250.250.3 ;; Query time: 0 msec ;; SERVER: 192.168.2.9#53(192.168.2.9) ;; WHEN: Wed Nov 10 14:33:37 2010 ;; MSG SIZE rcvd: 103

а виконавши:

Dig ya.ru | sed "0,/ANSWER SECTION:/d; /^$/q"

Ya.ru. 4160 IN A 93.158.134.3 ya.ru. 4160 IN A 213.180.204.3 ya.ru. 4160 IN A 77.88.21.3 ya.ru. 4160 IN A 87.250.250.3 ya.ru. 4160 IN A 87.250.251.3

    0,/ANSWER SECTION:/d - видаляє всі рядки потоку з першого і до рядка, в якому зустрічається "ANSWER SECTION:", включно

    /^$/q - щойно зустрічається порожній рядок, припинити подальшу обробку.

Приклади 1

Підготовка:

Cat /etc/passwd > ./test

SEDОпис
cat./test | sed -e "s/systemd/SysV/g; s/Management/Unmanaged/"До кожного рядка застосувати дві заміни
cat./test | sed -n "s/systemd/SysV/p"Вивести лише рядки, що замінюються. -n - пригнічує нормальний висновок.
cat./test | sed "s/systemd/SysV/w ./out"Вивести заміну у файл out
cat./test | sed "41s/systemd/SysV/"Здійснити заміну в 41 рядку
cat./test | sed "41,44s/systemd/SysV/"Здійснити заміну у рядках з 41 по 44 включно.
cat./test | sed "41,$s/systemd/SysV/"Здійснити заміну в рядках з 41 до останньої включно.
cat./test | sed "/games/,/syslog/ s!/usr/sbin/nologin!/bin/bash!"Здійснити заміну в рядках, які знаходяться між рядками, що містять games і syslog включно
cat./test | sed "1c\DELETED"Замінити перший рядок повність
cat./test | sed "1,5c\DELETED"Замінити текстом рядки з 1 до 5 включно
cat./test | sed "y!:/!;\\!"Замінити ":" на ";", а "/" на "\"
cat./test | sed "="Вивести і номери рядків теж
cat./test | sed -n "/systemd/="Вивести номери рядків, у яких зустрічається підрядок
Вставити в потік вміст файлу (out):
cat./test | sed "1rout"після 1 рядка
cat./test | sed "$r out"після останнього рядка
cat./test | sed "1,4rout"після 1, 2, 3 та 4 рядків
cat./test | sed "/syslog/r out"після рядка, що містить syslog
Видалити рядки:
cat./test | sed "/games/,/syslog/d"які знаходяться між рядками, що містять games та syslog включно
cat./test | sed "3,5d"з 3 по 5
cat./test | sed "5,$d"з 5 до кінця

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 текст- додати новий рядок із текстом після зазначеного рядка

$cat sed_test sed_test_1 11111 sed_test_2 22222 sed_test_3 33333 $ sed -e "2 a new_line" sed_test sed_test_1 11111 sed_test_2 22222 new_line sed

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

$ sed -e "2 з new_line" sed_test sed_test_1 11111 new_line sed_test_3 33333 $ sed -e "/3/ з new_line" sed_test sed_test_1 11111 sed_test_2 22222 new_

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

$ sed -e "2 d" sed_test sed_test_1 11111 sed_test_3 33333 $ sed -e "2! d" sed_test sed_test_2 22222

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

$ sed -e "2 i new_line" sed_test sed_test_1 11111 new_text sed_test_2 22222 sed_test_3 33333

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

$ sed -ne "2p" sed_test sed_test_2 22222

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

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

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

  • g - у всьому рядку
  • i - без урахування регістру
  • p - виводити результат заміни
$ sed -ne "s/t/T/g" sed_test sed_TesT_1 11111 sed_TesT_2 22222 sed_TesT_3 33333 $ sed -e "s//d/g" sed_test sed_test_d ddddd sed_test_d

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

$ sed -ne "y/est/EST/g" sed_test SEd_TEST_1 11111 SEd_TEST_2 22222 SEd_TEST_3 33333

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

Мітки

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

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

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

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

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

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

$ cat tac.sed #!/usr/bin/sed -nf # починаючи з другого рядка, вміст буфера (який вже містить # всі попередні рядки) додається до поточного рядка. 1! G # при досягненні останнього рядка - друкуємо $ p # Заносимо дані в буфер знову h sed -nf tac.sed sed_test sed_test_3 33333 sed_test_2 22222 sed_test_1 11111

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

$cat count.sed #!/usr/bin/sed -nf $=

результат

$ sed -nf count.sed sed_test 3

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

$ cat revers.sed #!/usr/bin/sed -f # пропускаємо рядки з однієї літери /../! b # Перевертаємо рядок. Додаємо по порожньому рядку перед та після поточного. s/%$@~*!G4;:%#`.*$/\ &\ / # Переносимо перший символ в кінець # цикл працює поки в середньому рядку є символи. tx:x s/\(\\n.\)\(.*\)\(.\\n\)/\3\\2\\1/ tx #видаляємо зайві переноси рядків s/\\n// g

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

$ sed -f revers.sed sed_test 11111 1_tset_des 22222 2_tset_des 33333 3_tset_des

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

Детальніше про формат sed-скриптів можна дізнатися, прочитавши мануал man sedабо технічну документацію info 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: ,
Автор: Rares Aioanei
Дата публікації: 19 листопада 2011 року
Переклад: А. Кривошей
Дата перекладу: липень 2012 р.

Микола Ігнатушко перевірив на GNU sed version 4.2.1 у дистрибутиві Gentoo усі команди, згадані у цій статті. Не всі скрипти добре відпрацьовували на версії GNU sed. Але справа стосувалася дрібниць, які виправлені. Тільки скрипт із заміни hill на mountains довелося суттєво переробити.

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
Вставляє порожній рядок після кожного рядка у 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 -n "/\(3\)/p" file.txt

Друкує лише рядки з трьома послідовними цифрами

Sed "/boom/s/aaa/bb/" file.txt

Якщо знайдено "boom", замінити aaa на bb

Sed "17,/disk/d" file.txt

Видаляє всі рядки, починаючи з 17-го, до "disk". Якщо рядків із "disk" кілька, видаляє до першої з них.

Echo ONE TWO sed "s/one/unos/I"

Замінює one на unos незалежно від регістру, тому буде надруковано "unos TWO"

Sed "G; G" file.txt

Вставляє два порожні рядки після кожного рядка у 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/[ \t]*$//" 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

Стиснути всі послідовні порожні рядки до одного. Порожнього рядка згори не залишається.

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 -n "/regex/,+5p" file.txt

Виводить 5 рядків після рядка, що містить regex

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/|*, */||/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/\ltred\>/magenta/g; s/<blue\>/cyan/g; )" file.txt

Замінює лише між "from" та "until". Якщо областей "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. Порядок 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

Видаляє останній рядок кожного абзацу
Отримує заголовок листа. Іншими словами - видаляє все після першого порожнього рядка.

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



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

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

Основи роботи з sed

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

$ sed options file
За промовчанням sed застосовує вказані при викликі правила, виражені як набору команд, до STDIN . Це дозволяє передавати дані безпосередньо sed.

Наприклад, так:

$ echo "This is a test" | sed "s/test/another test/"
Ось що вийде під час виконання цієї команди.


Простий приклад виклику sed

У цьому випадку sed замінює слово "test" у рядку, переданому для обробки, словами "another test". Для оформлення правила обробки тексту, укладеного в лапки, використовуються прямі слеші. У нашому випадку застосована команда виду s/pattern1/pattern2/. Літера "s" - це скорочення слова "substitute", тобто - перед нами команда заміни. Sed, виконуючи цю команду, перегляне переданий текст і замінить знайдені в ньому фрагменти (про те, які саме, поговоримо нижче), що відповідають pattern1, на pattern2.

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

Нижче показаний файл, в якому міститься фрагмент тексту, та результати його обробки такою командою:

$ sed "s/test/another test" ./myfile


Текстовий файлта результати його обробки

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

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

Виконання наборів команд під час виклику sed

Для виконання кількох дій з даними використовуйте ключ -e під час виклику sed. Наприклад, як організувати заміну двох фрагментів тексту:

$ sed -e "s/This/That/; s/test/another test/" ./myfile


Використання ключа -e під час виклику sed

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

$ sed -e " > s/This/That/ > s/test/another test/" ./myfile
Ось що вийде після того, як команда, представлена ​​у такому вигляді, буде виконана.


Інший спосіб роботи з sed

Читання команд із файлу

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

Ось вміст файлу mycommands:

S/This/That/ s/test/another test/
Викликаємо sed, передавши редактору файл із командами та файл для обробки:

$ sed -f mycommands myfile
Результат при виклику такої команди аналогічний тому, що виходив у попередніх прикладах.


Використання файлу з командами під час виклику sed

Прапори команди заміни

Уважно подивіться на приклад.

$ sed "s/test/another test/" myfile
Ось що міститься у файлі, і що буде отримано після обробки sed.


Вихідний файл та результати його обробки

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

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

S/pattern/replacement/flags
Виконання цієї команди можна модифікувати кількома способами.

  • При передачі номера враховується порядковий номер входження шаблону в рядок, замінено саме це входження.
  • Прапор g вказує на те, що потрібно обробити всі входження шаблону, що є у рядку.
  • Прапор p вказує на те, що потрібно вивести вміст вихідного рядка.
  • Прапор виду w file вказує команді те що, що потрібно записати результати обробки тексту файл.
Розглянемо використання першого варіанта команди заміни, із зазначенням позиції замінного входження шуканого фрагмента:

$ sed "s/test/another test/2" myfile

Виклик команди заміни із зазначенням позиції замінного фрагмента

Тут ми вказали, як прапор заміни, число 2. Це призвело до того, що було замінено лише друге входження шуканого шаблону в кожному рядку. Тепер пробуємо прапор глобальної заміни - g:

$ sed "s/test/another test/g" myfile
Як видно з результатів висновку, така команда замінила всі входження шаблону тексту.


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

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

$ sed -n "s/test/another test/p" myfile
Як результат, при запуску sed у такій конфігурації на екран виводяться лише рядки (у нашому випадку – один рядок), у яких знайдено заданий фрагмент тексту.


Використання прапора команди заміни p

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

$ sed "s/test/another test/w output" myfile


Збереження результатів обробки тексту у файл

Добре видно, що під час роботи команди дані виводяться в STDOUT , у своїй оброблені рядки записуються файл, ім'я якого зазначено після w .

Символи-розділювачі

Уявіть, що потрібно замінити /bin/bash на /bin/csh у файлі /etc/passwd . Завдання не таке вже й складне:

$ sed "s/\/bin\/bash/\/bin\/csh/" /etc/passwd
Однак, виглядає все це не дуже добре. Вся справа в тому, що так як прямі слеші використовуються в ролі символів-розділювачів, такі ж символи в переданих sed рядках доводиться екранувати. В результаті страждає на читаність команди.

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

$ sed "s!/bin/bash!/bin/csh!" /etc/passwd
В даному випадку як роздільник використаний знак оклику, в результаті код легше читати і він виглядає куди охайніше, ніж раніше.

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

Досі ми викликали sed для обробки всього переданого редактору потоку даних. У деяких випадках за допомогою sed треба обробити лише якусь частину тексту - якийсь конкретний рядок або групу рядків. Для досягнення такої мети можна скористатися двома підходами:
  • Задати обмеження на номери рядків, що обробляються.
  • Вказати фільтр, відповідний якому рядки потрібно обробити.
Розглянемо перший підхід. Тут допустимо два варіанти. Перший, розглянутий нижче, передбачає вказівку номера одного рядка, який потрібно опрацювати:

$ sed "2s/test/another test/" myfile


Обробка лише одного рядка, номер який заданий під час виклику sed

Другий варіант - діапазон рядків:

$ sed "2,3s/test/another test/" myfile


Обробка діапазону рядків

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

$ sed "2,$s/test/another test/" myfile


Обробка файлу починаючи з другого рядка і до кінця

Для того щоб обробляти за допомогою команди заміни тільки рядки, що відповідають заданому фільтру, команду треба викликати так:

$ sed "/likegeeks/s/bash/csh/" /etc/passwd
За аналогією про те, що було розглянуто вище, шаблон передається перед ім'ям команди s .


Обробка рядків, що відповідають фільтру

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

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

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

Виклик команди виглядає так:

$ sed "3d" myfile
Ми хочемо, щоб з тексту було видалено третій рядок. Зверніть увагу на те, що не йдеться про файл. Файл залишиться незмінним, видалення відіб'ється лише на висновку, який сформує sed.


Видалення третього рядка

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

Ось як застосувати команду d до діапазону рядків:

$ sed "2,3d" myfile


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

А ось як видалити рядки, починаючи із заданої - і до кінця файлу:

$ sed "3,$d" myfile


Видалення рядків до кінця файлу

Рядки можна видаляти і за шаблоном:

$ sed "/test/d" myfile


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

При викликі d можна вказувати пару шаблонів - будуть видалені рядки, в яких зустрінеться шаблон, і рядки, що знаходяться між ними:

$ sed "/second/,/fourth/d" myfile


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

Вставлення тексту в потік

За допомогою sed можна вставляти дані в текстовий потік, використовуючи команди i та a:
  • Команда i додає новий рядок перед заданим.
  • Команда a додає новий рядок після заданого.
Розглянемо приклад використання команди i:

$ echo "Another test" | sed "i\First test "


Команда i

Тепер поглянемо на команду a:

$ echo "Another test" | sed "a\First test "


Команда a

Як видно, ці команди додають текст до або після даних потоку. Що якщо треба додати рядок десь посередині?

Тут нам допоможе вказівка ​​номера опорного рядка в потоці або шаблону. Врахуйте, що адресація рядків як діапазону тут не підійде. Викличемо команду i , вказавши номер рядка, перед яким треба вставити новий рядок:

$ sed "2i\This is the inserted line." myfile


Команда i із зазначенням номера опорного рядка

Зробимо те саме з командою a:

$ sed "2a\This is the appended line." myfile


Команда a із зазначенням номера опорного рядка

Зверніть увагу на різницю в роботі команд i та a. Перша вставляє новий рядок до зазначеного, друга - після.

Заміна рядків

Команда c дозволяє змінити вміст цілого рядка тексту потоку даних. При її виклику потрібно вказати номер рядка, замість якого до потоку треба додати нові дані:

$ sed "3c\This is a modified line." myfile


Заміна рядка цілком

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

$ sed "/This is/c Це changed line of text." myfile


Заміна рядків за шаблоном

Заміна символів

Команда y працює з окремими символами, замінюючи їх відповідно до переданих їй під час виклику даних:

$ sed "y/123/567/" myfile


Заміна символів

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

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

Якщо викликати sed, використавши команду = , утиліта виведе номери рядків у потоці даних:

$ sed "=" myfile


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

Поточний редактор вивів номери рядків перед вмістом.

Якщо передати цій команді шаблон і скористатися ключем sed -n , буде виведено лише номери рядків, що відповідають шаблону:

$ sed -n "/test/=" myfile


Виведення номерів рядків, які відповідають шаблону

Читання даних для вставки з файлу

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

Розглянемо приклад:

$ sed "3r newfile" myfile


Вставлення в потік вмісту файлу

Тут вміст файлу newfile було вставлено після третього рядка файлу myfile.

Ось що станеться, якщо застосувати під час виклику команди r шаблон:

$ sed "/test/r newfile" myfile


Використання шаблону під час виклику команди r

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

приклад

Уявімо собі таке завдання. Є файл, у якому є певна послідовність символів, як така безглузда, яку треба замінити на дані, взяті з іншого файла. А саме, нехай це буде файл newfile, в якому роль покажчика місця заповнення грає послідовність символів DATA. Дані, які потрібно підставити замість DATA, зберігаються у файлі data.

Вирішити це завдання можна, скориставшись командами r і d потокового редактора sed:

$ Sed "/DATA>/ (r newfile d)" myfile


Заміна вказівника місця заповнення на реальні дані

Як бачите, замість заповнювача DATA sed додав у вихідний потік два рядки з файлу data.

Підсумки

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

На сьогодні це все. Наступного разу поговоримо про мову обробки даних awk.

Шановні читачі! А ви користуєтесь sed у повсякденній роботі? Якщо так – поділіться будь ласка досвідом.

 

 

Це цікаво: