Введение в Linux и Bash, часть III

Published Jan 11, 2019 08:23 UTC on Yaroslav's weblog

Новый год, новый пост. В данной, третьей и последней, части этого туториала, будут несколько команд и программ которые являются стандартной частью большинства дистрибутивов Линукса. Больше всего внимания я буду выделять программ, которые манипулируют вывод текст других программ и файлов. Также в этом посте мы поговорим о регулярных выражений (коротко - regex, от английского Regular Expression), очень мощный инструмент для поиска текста

Фильтры

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

cat

Данная команда позволяет посмотреть содержимое текстового файла (или файлов). Название программы ни как не связанна с котейками, а происходит от слово конкатенация. Самое простое применение данной программы - просмотр текстовых файлов. Просто пишите cat а затем путь файла. Однако, как можно предположить исходя из названии программы, она также позволяет соединять несколько текстовых файлов или потоков в один. Например

user@host:~/Documents/notes$ cat sample.txt
Pepe    cool
Tide Pods   lame
Uganda Knuckles cool
Thanos  cool
JPEG    ok
Despacito   lame
Bowsette    cool
Harold  cool
Sans    coolest
Minions lamest
NPC cool

А теперь допустим что мы хотим соединить соджержимое данного файла с файлом 'sample2.txt'

user@host:~/Documents/notes$ cat sample.txt sample2.txt
Pepe    cool
Tide Pods   lame
Uganda Knuckles cool
Thanos  cool
JPEG    ok
Despacito   lame
Bowsette    cool
Harold  cool
Sans    coolest
Minions lamest
NPC cool
Troll Face  old
Can haz chezburger  really old
ROFLcopter  super old
Dancing baby    ancient

Как обычно, у данной команды есть несколько параметров, как например параметр -n чтобы показать номер строки

user@host:~/Documents/notes$ cat -n sample.txt
     1  Pepe    cool
     2  Tide Pods   lame
     3  Uganda Knuckles cool
     4  Thanos  cool
     5  JPEG    ok
     6  Despacito   lame
     7  Bowsette    cool
     8  Harold  cool
     9  Sans    coolest
    10  Minions lamest
    11  NPC cool

И как я уже рассказывал в предыдущей части, вы можете узнать больше о команде, используя программу man ('man cat').

Данная команда довольно простая, она показывает первые n строки текстового файла/потока. Введите head, затем -n и количество строк вы желаете увидеть, а затем петь файла. Например, допустим что мы хотим увидеть первые 5 строк

user@host:~/Documents/notes$ head -n 5 sample.txt
Pepe    cool
Tide Pods   lame
Uganda Knuckles cool
Thanos  cool
JPEG    ok

Если мы не передаем количетсво строк, по умолчанию она выводит первые 10 строк. Для просто напишите head а затем путь файла.

tail

Работает также как head, но в отличие от нее, данная команда показывает последние строки текста. Допустим мы хотим увидеть последние три строки

user@host:~/Documents/notes$ tail -n 3 sample.txt
Sans    coolest
Minions lamest
NPC cool

Также как и с предыдущей командой, по умолчанию выводятся 10 строк.

sort

С данной командой все очень просто. Она сортирует текст. Например

user@host:~/Documents/notes$ sort sample.txt
Bowsette    cool
Despacito   lame
Harold  cool
JPEG    ok
Minions lamest
NPC cool
Pepe    cool
Sans    coolest
Thanos  cool
Tide Pods   lame
Uganda Knuckles cool

sed

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

Для работы с данной программой, необходимо передать своего рода скрирта (sed script), который укажет программе что делать с текстом. Первый и самый простой способ использовать sed, это использовать его в качестве программы head, то есть, получить первые b строк текста. Например, допустим что нам необходимо получить первые 7 строк из файла sample.txt

user@host:~/Documents/notes$ sed '7q' sample.txt
Pepe    cool
Tide Pods   lame
Uganda Knuckles cool
Thanos  cool
JPEG    ok
Despacito   lame
Bowsette    cool

А если более подробно объяснить что данная команда делает, то она говорит программе чтобы она вывела 7 строк, и затем вышла (q).

Другой случай, и сокрее всего самое распространенное применение данной команды, это операция поиска и замены текста. Основная синтаксис данной операции выгладит следующим образцом - 's/<поиск>/<замена>/'.

По умолчанию данная команда заменяет только первое совпадение в каждой строке, тем не менее мы может указать какие и сколько совпадении мы хотим заменить. Например, если мы добавим двойку в конце команды ('s///2') она заменит только вторые совпадения в каждой строке.

Но а что если мы хотим заменить все совпадения во всех строках? Все очень просто - достаточно добавить букву g в конец. Допустим что мы хотим заменить все подстроки "cool" на "dank" в файле sample.txt

user@host:~/Documents/notes$ sed 's/cool/dank/g' sample.txt
Pepe    dank
Tide Pods   lame
Uganda Knuckles dank
Thanos  dank
JPEG    ok
Despacito   lame
Bowsette    dank
Harold  dank
Sans    dankest
Minions lamest
NPC dank

Обратите внимание на то что команду которую мы передаем sed'у находится в кавычках. Конечно это только одни из самых основных применении.

grep

Это последняя программа-фильтр, о которой я расскажу. Я покажу самое основное применение данной программы, а затем, после того как расскажу о регулярных выражений, покажу ее более интересные применения.

grep - программа, которая выполняет поиск выражения переданный ей пользователем, и выводит на экран строки, совпадавшие с условиями поиска. Допустим, например, что мы хотим увидеть только крутые (cool) мемы

user@host:~/Documents/notes$ grep 'cool' sample.txt
Pepe    cool
Uganda Knuckles cool
Thanos  coolcharacter
Bowsette    cool
Harold  cool
Sans    coolest
NPC cool

То, что мы передали grep'у является самым простым видом регулярного выражения. По факту мы указали программе чтобы нам показала строки где содержится подстрока "cool".

Регулярные выражения

Регулярное выражение - язык поиска и манипуляции подстроками в тексте. Для поиска используется строка текста, часто называемая строка-образец или "шаблон", состоящая из символов, которые задают правило поиска. Регулярные выражения применяются в многих программах и языках программирования, таких как например редакторов текста и поисков, и естественно, может быть довольно полезным в терминале.

Антракт

Перед тем как объяснить как работать с регулярными выражениями, хочу показать пару символов, облегчающие жизнь при работе с файлами в терминале - символы-джокеры (на англ. wildcards). В терминале они - звездочка (*) и вопросительный знак (?). Как раз из-за их специального применения, их нельзя использовать в названиях файлов.

Начнем со звездочки. Звездочка озночает что на ее месте может быть любое количество любых символов. Например, чтобы искать файлы, чье название начинается с sa

user@host:~/Documents/notes$ ls sa*
saturday.txt sample.txt sample2.txt sample.png

Другой пример, найти файлы чье название просто содержит подстроку sa

user@host:~/Documents/notes$ ls *sa*
asado.png saturday.txt sample.txt sample2.txt sample.png

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

user@host:~/Documents/notes$ ls sample.???
sample.txt sample.png

Символы-джокеры очень полезные когда необходимо манипулировать несколько файлов с похожими названиями. Однако, если названия файлов не похоже никак, нам придется использовать фигурные скобки, чтобы указать список файлов. Например

user@host:~/Documents/notes$ rm {monday.txt,december1999.txt,saturday.txt}

Обратно к regex

А теперь я объясню основные части и символы регулярных выражении, а затем вам покажу как их использовать в grep

  • . - Точка означает один символ (любой символ). Например, 'be.r' найдет нам bear, beer, befr, и т.д.
  • * - Предыдущий элемент совпадает 0 или больше раз. Например 'an*t' нам найдет at, ant, annt, annnt, и т.д.
  • + - Предыдущий элемент совпадает один или больше раз. Например 'an+t' нам найдет ant, annt, annt, и т.д.
  • ? - Предыдущий элемент совпадает 0 или один раз. Например 'an?t' нам найдет at и ant.
  • {n} - Предыдущий элемент совпадает ровно n раз.
  • {min, } - Предыдущий элемент совпадает хотя бы min раз
  • {min, max} - Предыдущий элемент совпадает хотя бы min раз и не больше max раз.
  • | - Логический оператор ИЛИ. Например, 'gray|grey' нам найдет gray и grey.
  • () - Круглые скобки группируют несколько символов в один элемент. Например 'gr(a|e)y' нам найдет gray и grey.
  • [abc] - Совпадает если один из символов, который внутри скобок, присуствует.
  • [^abc] - Совпадает если нет ни одного, из которых внутри скобок.
  • [a-d] - Диапазон символов. То есть a, b, c и/или d.
  • ^ - Начало строки.
  • $ - Конец строки.

А теперь, ради примера с grep, допустим что, мы хотим найти все строки в которых содержится "cool" или "ok" в них. В этом случае нам нужна вертикальная черта "|". Однако, если использовать grep без параметров, нам нужно будет напечатать слеш перед ней "|". Поэтому лучше использовать команду egrep, которая является сокращением "grep -E", затем чтобы включить расширенные регулярные выражения. Например

user@host:~/Documents/notes$ egrep 'cool|ok' sample.txt
Pepe    cool
Uganda Knuckles cool
Thanos  cool
JPEG    ok
Bowsette    cool
Harold  cool
Sans    coolest
NPC cool

А теперь допустим что, нам неоюходимо найти все строки с буквой 't' в качестве последнего символа в строке

user@host:~/Documents/notes$ egrep 't$' sample.txt
Sans    coolest
Minions lamest

Я уже продемонстрировал применение regex'ов с grep'ом (и/или egrep). А теперь я хочу вам показать более практический пример с sed'ом. Да, в sed'e помимо собственного языка, можно еще и регулярные выражения использовать.

Допустим у нас есть файл который выглядит следующим образом

user@host:~/Documents/notes$ cat shortcuts
# Some shortcuts

d       ~/Documents
D       ~/Downloads
m       ~/Music
pp      ~/Pictures
vv      ~/Videos


s       ~/.scripts # My scripts
cf      ~/.config # My configs

Как вы могли заметить, в нашем файле много пустых строк, и много комментарри, которые полезные для человека, но бесполезные для компьютера. Начнем с того что, удалим комментарии, для этого мы будем использовать команду sed'а для поиска и замены, только в нашем случае мы хотим заменить комментарии на пустоту. Затем нам понадобится вставить регулярное выражение, которое поможет нам найти комментарии - '#.*'. Этот шаблон переводится как - найди символ '#' и все что после него находится. А теперь давайте мы все совместим

user@host:~/Documents/notes$ sed 's/#.*//g' shortcuts


d       ~/Documents
D       ~/Downloads
m       ~/Music
pp      ~/Pictures
vv      ~/Videos


s       ~/.scripts
cf      ~/.config

Вот и мы избавились от комментариев. Тем не менее нам еще осталось избавится от пустых строк, и если вы заметили, комментарии были удалены, но перед некоторыми из них остались пробелы.

И так, давайте мы сначала улучшим нашу команду, для этого нам нужно найти там где есть 0 или больше пробелов перед комментарии, но как нам обозначит пробелы в sed'е? Все очень просто с '\s', таким образом наша команда а теперь выглядет вот так 's/\s*#.*//g'.

А теперь нам нужно избавится от пустых строк. Для этого нам нужно ввести еще одну команду sed'а, но мы можем ее ввести вместе с предыдущей командой отделяя их точкой и запетой (;). Нам осталось придумать как найти пустую строку, все очень просто - '^$', то есть, найти ту строку где ее начало и ее конец находятся вместе. Нам осталось указать sed чтобы он удалил эту строку, и вот я вам расскажу еще одну команду sed - команду для удаления (d), и так...

user@host:~/Documents/notes$ sed 's/\s*#.*//g; /^$/d' shortcuts
d       ~/Documents
D       ~/Downloads
m       ~/Music
pp      ~/Pictures
vv      ~/Videos
s       ~/.scripts
cf      ~/.config

Конечно, когда мы вводим эту команду, она не переписывает файл, она всего лишь выводит на экран результат операции. Если вам необходимо переписать исходный файл вы можете передать sed параметр '-i.

Конвейер и перенаправление

Последнее о чем я буду писать в этом туториале не команда и не программа, но очень полезная вещь, которая есть во всех Unix и Unix-подобных системах - конвейер. Конвейер - это цепочка перенаправляющая вывод процесса или процессов в стандартный ввод других процессов. В том числе есть и операторы которые позволяют перенаправлять вывод программы в файл и наоборот.

Перенаправление в и из файлов

Допустим что мы хотим повторить последний пример, но в этот раз мы хотим записать результат в файл. Мы уже знаем как переписать оригинальный файл, но в этот раз мы хотим записать результат в новый файл. Для этого нам понадобятся операторы перенаправления Unix'а '>' и '>>'. Первый оператор переписывает файл, если указанный файл уже существует, а второй просто добавляет поток текста в конец файла. В этом случае безразлично какой из этих операторов использовать, ибо мы хотим записать поток текста на новый файл

user@host:~/Documents/notes$ sed 's/\s*#.*//g; /^$/d' shortcuts > shortcuts_clean

Так же существует оператор перенаправления ИЗ файла в стандартный ввод программы - '<'. Однако, в большинство случаях достаточно передать путь файла в качестве аргумента.

Конвейер

А теперь я вам покажу как перенаправить вывод одной программы в другую. Чтобы перенаправить вывод из одной программы в другую, достаточно ввести команду первой программы, затем ввести вертикальную черту (|), а затем команду второй программы. Допустим мы хотим увидит первые три файлы в нашей директории, для этого мы можем направить вывод ls в head, вот так

user@host:~/Documents/notes$ ls | head -n 3
asado.png
monday.txt
sample.txt

А теперь вернемся к файлу sample.txt. Допустим что сначала мы хотим отсортировать все строки файла, и хотим оставить только те строки с "cool" и "lame". Затем, мы хотим заменить неправильные старые термины, на современные, то есть "cool" на "dank" и "lame" на "normie". И наконец, мы хотим это сохранить в файл. И вот как все это выгладит

user@host:~/Documents/notes$ egrep 'cool|lame' sample.txt | sort | sed 's/cool/dank/g;s/lame/normie/g' > memes.txt

Взглядываем в файл и...

user@host:~/Documents/notes$ cat memes.txt
Bowsette    dank
Despacito   normie
Harold  dank
Minions normiest
NPC dank
Pepe    dank
Sans    dankest
Thanos  dank
Tide Pods   normie
Uganda Knuckles dank

И вот и все

Post scriptum

Перед тем как закончить с этим туториалом, я хочу вам показать еще несколько программ, которые могут вам пригодится

less

Данная команда вам пригодится когда, например, некоторая программа выводит слишком много текста. В таком случае, достаточно перенаправить вывод текста первой программы к less используя оператор конвейера (|), также как я вам только что показал. Используя эту команду вы можете листать текст используя стрелочки или vim-клавиши (hjkl). Так же вы можете искать термины введя слеш (/).

tar

Это de facto официальная программа Линукса для архивирования и сжатия файлов в формате .tar. Чаще всего используется формат сжатия gunzip (.gz), но есть и другие форматы сжатия.

Есть два основных способов использовать эту программу. Первый чтобы разархивировать

user@host:~/Documents/notes$ tar -xzvf oldnotes.tar.gz

Второй чтобы архивировать и сжать

user@host:~/Documents/notes$ tar -czvf allnotes.tar.gz *

Как обычно, вы можете узнать больше об этой программе используя утилиту man ('man tar').

ssh and scp

Скорее всего вы уже слышали или даже работали с ssh, даже если вы не работали до этого с Ликусом или Unix/Unix-подобных системах. Это программа позволяет подключится через терминал к другим компьютером через сеть (например, интернет), в том числе и к серверам.

Допустим вы хотите подключится к серверу с ip 180.80.8.20 и пользователь tux

user@host:~$ ssh tux@180.80.8.20

Здесь мы предполагаем что мы подключаемся через стандартный порт ssh (22), иначе придется его передать используя параметр -p а затем номер порта.

А теперь поговорим о scp. Это программа позволяет передать файлы из одного компьютера в другого используя протокол ssh'а. Допустим что мы хотим отправить файл с локального компьютер в тот же самый сервер, что и в прошлом примере

user@host:~$ scp somefile tux@180.80.8.20:/home/tux/directory/

Если бы мы хотели наоборот, получить, а не отправить, то мы просто поменяли порядок аргументов, примерно вот так

user@host:~$ scp tux@180.80.8.20:/home/tux/directory/somefile directory/

Так же как и с ssh порт по умолчанию 22, то есть если использовать другой порт, нужно его указать, только в отличие от ssh, параметр -P вместо -p и нужно его ввести сразу после "scp.

Вот и на этом все. Надеюсь вам этот туториал помог. С наступившим 2019.