Как да използвам командата sed на Linux

Може да звучи налудничаво, но sedкомандата на Linux е текстов редактор без интерфейс. Можете да го използвате от командния ред за манипулиране на текст във файлове и потоци. Ще ви покажем как да използвате нейната сила.

Силата на сед

В sedзаповедта е малко като шах: тя отнема един час, за да се научат основите и цял живот да ги овладеят (или поне много практика). Ще ви покажем селекция от отварящи се гамбити във всяка от основните категории sedфункционалност.

sedе редактор на потоци, който работи върху въведени в тръбопровод или файлове с текст. Той обаче няма интерактивен интерфейс за текстов редактор. По-скоро предоставяте инструкции, които трябва да следва, докато работи в текста. Всичко това работи в Bash и други обвивки на командния ред.

С това sedможете да направите всичко следното:

  • Изберете текст
  • Заместващ текст
  • Добавете редове към текста
  • Изтриване на редове от текста
  • Променете (или запазете) оригинален файл

Ние структурирахме нашите примери, за да въведем и демонстрираме концепции, а не да произвеждаме най-кратките (и най-малко достъпните) sedкоманди. Функциите за съвпадение на шаблони и избор на текст обаче sed разчитат много на регулярни изрази (регулярни изрази). Ще ви трябва познаване с тях, за да извлечете най-доброто от тях sed.

СВЪРЗАНИ: Как да използвам регулярни изрази (регулярни изрази) в Linux

Един прост пример

Първо, ще използваме echoза изпращане на някакъв текст sedпрез тръба и ще sed заменим част от текста. За целта въвеждаме следното:

echo howtogonk | sed 's / gonk / geek /'

В echoкоманда изпраща "howtogonk" в sed, и (на "S", стендове за смяна) се нанася ни просто правило смяна. sed търси входния текст за поява на първия низ и ще замени всички съвпадения с втория.

Низът "gonk" се заменя с "geek" и новият низ се отпечатва в прозореца на терминала.

Заместванията са може би най-честата употреба на sed. Преди да можем да се потопим по-дълбоко в заместванията обаче, трябва да знаем как да избираме и да съпоставяме текста.

Избиране на текст

Ще се нуждаем от текстов файл за нашите примери. Ще използваме такъв, който съдържа селекция от стихове от епичната поема на Самюел Тейлър Колридж „The Rime of the Ancient Mariner“.

Въвеждаме следното, за да го разгледаме с less:

по-малко coleridge.txt

За да изберете някои редове от файла, ние предоставяме началните и крайните редове на диапазона, който искаме да изберем. Едно число избира този ред.

За да извлечем редове от един до четири, въвеждаме тази команда:

sed -n '1,4p' coleridge.txt

Обърнете внимание на запетая между 1и 4. В pсредствата "печатат съвпадащи линии." По подразбиране  sed отпечатва всички редове. Ще видим целия текст във файла със съответстващи редове, отпечатани два пъти. За да предотвратим това, ще използваме опцията -n(тихо), за да потиснем ненадминатия текст.

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

sed -n '6,9p' coleridge.txt

Можем да използваме опцията -e(израз), за да направим множество селекции. С два израза можем да изберем два стиха, така:

sed -n -e '1,4p' -e '31, 34p 'coleridge.txt

Ако намалим първото число във втория израз, можем да вмъкнем празно място между двата стиха. Въвеждаме следното:

sed -n -e '1,4p' -e '30, 34p 'coleridge.txt

Също така можем да изберем начален ред и да кажем sed да преминем през файла и да отпечатаме алтернативни редове, всеки пети ред или да пропуснем произволен брой редове. Командата е подобна на тази, която използвахме по-горе за избор на диапазон. Този път обаче ще използваме тилда ( ~) вместо запетая, за да отделим числата.

Първото число показва стартовия ред. Второто число казва sedкои редове след стартовия ред искаме да видим. Числото 2 означава всеки втори ред, 3 означава всеки трети ред и т.н.

Въвеждаме следното:

sed -n '1 ~ 2p' coleridge.txt

Не винаги ще знаете къде се намира текстът, който търсите във файла, което означава, че номерата на редовете не винаги ще са от голяма помощ. Можете обаче да използвате и sed за избор на редове, които съдържат съвпадащи текстови модели. Например, нека извлечем всички редове, които започват с „И“.

Каретката ( ^) представлява началото на реда. Ще приложим думата си за търсене в наклонени черти ( /). Също така включваме интервал след „И“, така че думи като „Android“ няма да бъдат включени в резултата.

Четенето на sedскриптове може да бъде малко трудно в началото. Най /p средства "Печат", точно както го направи в команди, които използвахме по-горе. В следната команда обаче наклонена черта я предхожда:

sed -n '/ ^ И / p' coleridge.txt

Три реда, които започват с „И“, се извличат от файла и се показват за нас.

Правене на замествания

В първия ни пример ви показахме следния основен формат за sedзаместване:

echo howtogonk | sed 's / gonk / geek /'

Най sказва sed това е смяна. Първият низ е шаблонът за търсене, а вторият е текстът, с който искаме да заменим съответстващия текст. Разбира се, както при всички неща Linux, дяволът е в детайлите.

Въвеждаме следното, за да променим всички случаи на „ден“ на „седмица“ и даваме на моряка и албатроса повече време за свързване:

sed -n 's / ден / седмица / p' coleridge.txt

В първия ред се променя само втората поява на „ден“. Това е така, защото sedспира след първия мач на ред. Трябва да добавим „g“ в края на израза, както е показано по-долу, за да извършим глобално търсене, така че всички съвпадения във всеки ред да бъдат обработени:

sed -n 's / day / week / gp' coleridge.txt

Това съвпада с три от четирите на първия ред. Тъй като първата дума е „Ден“ и sedе чувствителна към малки и големи букви, тя не счита този екземпляр за същото като „ден“.

Въвеждаме следното, добавяйки i към командата в края на израза, за да посочим нечувствителност към регистъра:

sed -n 's / day / week / gip' coleridge.txt

Това работи, но може би не винаги искате да включите нечувствителност към малки и малки букви за всичко. В тези случаи можете да използвате група регулярни изрази, за да добавите специфична за модела нечувствителност към случая.

Например, ако заградим символи в квадратни скоби ( []), те се тълкуват като „всеки символ от този списък с символи“.

Въвеждаме следното и включваме „D“ и „d“ в групата, за да гарантираме, че съвпада и с „Ден“, и с „ден“:

sed -n 's / [Dd] ay / седмица / gp' coleridge.txt

Също така можем да ограничим заместванията до раздели на файла. Да приемем, че нашият файл съдържа странни интервали в първия стих. Можем да използваме следната позната команда, за да видим първия стих:

sed -n '1,4p' coleridge.txt

Ще търсим две интервали и ще ги заменим с едно. Ще направим това глобално, така че действието да се повтаря по цялата линия. За да бъде ясно, шаблонът за търсене е интервал, звездичка ( *), а низът за заместване е единичен интервал. В 1,4ограничава замяна на първите четири линии на файла.

Събрахме всичко това в следната команда:

sed -n '1,4 s / * / / gp' coleridge.txt

Това работи добре! Моделът на търсене е най-важното тук. Звездичката ( *) представлява нула или повече от предходния знак, който е интервал. По този начин моделът за търсене търси низове от едно или повече пространства.

Ако заменим единично интервал за произволна последователност от множество интервали, ще върнем файла на редовен интервал, с едно интервал между всяка дума. Това в някои случаи също ще замести единично пространство с едно пространство, но това няма да повлияе на нищо неблагоприятно - все пак ще получим желания резултат.

Ако напишем следното и намалим модела на търсене до едно пространство, веднага ще видите защо трябва да включим две интервали:

sed -n '1,4 s / * / / gp' coleridge.txt

Тъй като звездичката съвпада с нула или повече от предходния знак, тя вижда всеки знак, който не е интервал, като „нулево интервал“ и прилага заместването към него.

Ако обаче включим две интервали в шаблона за търсене,  sedтрябва да намерим поне един интервал преди да приложи заместването. Това гарантира, че непространствените символи ще останат недокоснати.

Въвеждаме следното, използвайки -e(израза), който използвахме по-рано, което ни позволява да правим две или повече замествания едновременно:

sed -n -e 's / motion / flutter / gip' -e 's / ocean / gutter / gip' coleridge.txt

Можем да постигнем същия резултат, ако използваме точка и запетая ( ;) за разделяне на двата израза, по следния начин:

sed -n 's / motion / flutter / gip; s / ocean / gutter / gip' coleridge.txt

Когато сменихме „ден“ с „седмица“ в следната команда, инстанцията на „ден“ в израза „добре на ден“ също беше разменена:

sed -n 's / [Dd] ay / седмица / gp' coleridge.txt

За да предотвратим това, можем да опитваме замествания само на линии, които съответстват на друг модел. Ако модифицираме командата, за да има шаблон за търсене в началото, ще обмислим само опериране на редове, които съответстват на този шаблон.

Въвеждаме следното, за да направим нашия модел на съвпадение думата „след“:

sed -n '/ after / s / [Dd] ay / week / gp' coleridge.txt

Това ни дава отговора, който искаме.

По-сложни замествания

Нека дадем на Coleridge почивка и използваме sedза извличане на имена от etc/passwdфайла.

Има по-кратки начини да направите това (повече за това по-късно), но ще използваме по-дългия път тук, за да демонстрираме друга концепция. Всеки съвпадащ елемент в шаблона за търсене (наречен субекспресии) може да бъде номериран (до максимум девет елемента). След това можете да използвате тези числа в  sedкомандите си, за да се позовавате на конкретни под изрази.

Трябва да приложите субекспресията в скоби [ ()], за да работи това. Скобите също трябва да бъдат предшествани от наклонена черта ( \), за да се предотврати тяхното третиране като нормален знак.

За да направите това, трябва да въведете следното:

sed 's / \ ([^:] * \). * / \ 1 /' / etc / passwd

Нека разбием това:

  • sed 's/: Най- sedкоманда и началото на изразяването на заместването.
  • \(: Отварящата скоба [ (], затваряща подвиражението, предшествана от наклонена черта ( \).
  • [^:]*: Първият подизраз на думата за търсене съдържа група в квадратни скоби. Каретката ( ^) означава „не“, когато се използва в група. Група означава, че всеки знак, който не е двоеточие ( :), ще бъде приет като съвпадение.
  • \): Затварящата скоба [ )] с предходна наклонена черта ( \).
  • .*: Този втори подизраз на търсене означава „произволен знак и произволен брой от тях“.
  • /\1: Заместващата част на израза съдържа 1предшествана от наклонена черта ( \). Това представлява текстът, който съответства на първия подизраз.
  • /': Затварящата наклонена черта ( /) и единична кавичка ( ') прекратяват sedкомандата.

Всичко това означава, че ще търсим всеки низ от символи, който не съдържа двоеточие ( :), което ще бъде първият случай на съвпадащ текст. След това търсим нещо друго на този ред, което ще бъде втората инстанция на съвпадащ текст. Ще заместим целия ред с текста, който съответства на първия подизраз.

Всеки ред във /etc/passwdфайла започва с потребителско име, прекратено с двоеточие. Съпоставяме всичко до първото двоеточие и след това заместваме тази стойност за целия ред. И така, изолирахме потребителските имена.

След това ще приложим втория подизраз в скоби [ ()], за да можем да го посочим и с номер. Ние също ще заменим \1 с \2. Нашата команда сега ще замести целия ред с всичко от първото двоеточие ( :) до края на реда.

Въвеждаме следното:

sed 's / \ ([^:] * \) \ (. * \) / \ 2 /' / etc / passwd

Тези малки промени обръщат значението на командата и ние получаваме всичко, с изключение на потребителските имена.

Сега, нека да разгледаме бързия и лесен начин за това.

Нашата дума за търсене е от първото двоеточие ( :) до края на реда. Тъй като нашият заместващ израз е празен ( //), ние няма да заменим съответстващия текст с нищо.

И така, въвеждаме следното, като отрязваме всичко от първото двоеточие ( :) до края на реда, оставяйки само потребителските имена:

sed 's /:.*// "/ etc / passwd

Нека разгледаме пример, в който препращаме първото и второто съвпадение в една и съща команда.

Имаме файл със запетаи ( ,), разделящ собственото и фамилното име. Искаме да ги посочим като „фамилия, име“. Можем да използваме  cat, както е показано по-долу, за да видим какво има във файла:

cat geeks.txt

Както много sedкоманди, и тази следваща може да изглежда непроницаема в началото:

sed 's / ^ \ (. * \), \ (. * \) $ / \ 2, \ 1 / g' geeks.txt

Това е команда за заместване като другите, които сме използвали, и моделът за търсене е доста лесен. Ще го разделим по-долу:

  • sed 's/: Нормалната команда за заместване.
  • ^: Тъй като каретката не е в група ( []), това означава „Началото на линията.“
  • \(.*\),: Първият подизраз е произволен брой символи. Той е затворен в скоби [ ()], всеки от които се предшества от наклонена черта ( \), за да можем да го препращаме по номер. Целият ни модел на търсене досега се превежда като търсене от началото на реда до първата запетая ( ,) за произволен брой символи.
  • \(.*\):  Следващият подизраз е (отново) произволен брой от произволен символ. Също така е затворено в скоби [ ()], и двете се предшестват от наклонена черта ( \), за да можем да препращаме съответния текст по номер.
  • $/: Знакът за долар ( $) представлява края на реда и ще позволи на нашето търсене да продължи до края на реда. Използвахме това просто, за да въведем знака за долар. Наистина нямаме нужда от него тук, тъй като звездичката ( *) ще отиде в края на реда в този сценарий. Наклонената черта ( /) завършва раздела за модел на търсене.
  • \2,\1 /g': Тъй като затворихме двата си подвиражения в скоби, можем да се позовем и на двамата по техните номера. Тъй като искаме да обърнем реда, ние ги въвеждаме като second-match,first-match. Числата трябва да бъдат предшествани от наклонена черта ( \).
  • /g: Това дава възможност на нашата команда да работи глобално на всеки ред.
  • geeks.txt: Файлът, по който работим.

Можете също да използвате командата Cut ( c), за да заместите цели редове, които съответстват на вашия модел на търсене. Въвеждаме следното, за да търсим ред с думата „neck“ в него, и го заменяме с нов низ от текст:

sed '/ шия / c Около китката ми беше нанизан' coleridge.txt

Новият ни ред сега се появява в долната част на извлечението.

Вмъкване на редове и текст

Също така можем да вмъкнем нови редове и текст в нашия файл. За да вмъкнем нови редове след съответстващи, ще използваме командата Append ( a).

Ето файла, с който ще работим:

cat geeks.txt

Номерирахме редовете, за да улесним това.

Въвеждаме следното, за да търсим редове, които съдържат думата „Той“, и вмъкваме нов ред под тях:

sed '/ Той / а -> Вмъкнат!' geeks.txt

Въвеждаме следното и включваме Insert Command ( i), за да вмъкнем новия ред над тези, които съдържат съвпадащ текст:

sed '/ He / i -> Вмъкнато!' geeks.txt

Можем да използваме амперсанд ( &), който представлява оригиналния съвпадащ текст, за да добавим нов текст към съответстващ ред. \1 ,,  \2и така нататък, представляват съвпадащи подекспресии.

За да добавим текст в началото на ред, ще използваме команда за заместване, която съответства на всичко по реда, комбинирана с клауза за заместване, която комбинира новия ни текст с оригиналния ред.

За да направим всичко това, въвеждаме следното:

sed 's /.*/--> Вмъкна & /' geeks.txt

Въвеждаме следното, включително Gкомандата, която ще добави празен ред между всеки ред:

sed 'G' geeks.txt

Ако искате да добавите два или повече празни редове, можете да използвате G;GG;G;Gи така нататък.

Изтриване на редове

Командата Delete ( d) изтрива редове, които съответстват на шаблон за търсене, или тези, посочени с номера на редове или диапазони.

Например, за да изтрием третия ред, ще напишем следното:

sed '3d' geeks.txt

За да изтрием диапазона от редове от четири до пет, ще напишем следното:

sed '4,5d' geeks.txt

За да изтрием редове извън диапазон, използваме удивителен знак ( !), както е показано по-долу:

sed '6,7! d' geeks.txt

Запазване на вашите промени

Досега всички наши резултати са отпечатани в прозореца на терминала, но все още не сме ги запазили никъде. За да ги направите постоянни, можете или да напишете промените си в оригиналния файл, или да ги пренасочите към нов.

Презаписването на оригиналния файл изисква известна предпазливост. Ако вашата sedкоманда е грешна, може да направите някои промени в оригиналния файл, които е трудно да се отменят.

За малко спокойствие sed можете да създадете резервно копие на оригиналния файл, преди да изпълни командата си.

Можете да използвате опцията In-place ( -i), за да кажете  sedда напишете промените в оригиналния файл, но ако добавите разширение към него, sed ще архивирате оригиналния файл в нов. Той ще има същото име като оригиналния файл, но с ново разширение на файла.

За демонстрация ще потърсим всички редове, които съдържат думата „Той“ и ще ги изтрием. Също така ще архивираме оригиналния си файл в нов, като използваме разширението BAK.

За да направим всичко това, въвеждаме следното:

sed -i'.bak '' /^.*He.*$/d 'geeks.txt

Въвеждаме следното, за да сме сигурни, че архивният ни файл е непроменен:

cat geeks.txt.bak

Можем също да напишем следното, за да пренасочим изхода към нов файл и да постигнем подобен резултат:

sed -i'.bak "" /^.*He.*$/d 'geeks.txt> new_geeks.txt

Използваме, за catда потвърдим, че промените са записани в новия файл, както е показано по-долу:

котка new_geeks.txt

Като имам всичко това

Както вероятно сте забелязали, дори този бърз грунд sedе доста дълъг. Тази команда има много неща и можете да направите още повече с нея.

Надяваме се обаче, че тези основни концепции осигуряват стабилна основа, върху която можете да надграждате, докато продължавате да научавате повече.