aboutsummaryrefslogtreecommitdiff
path: root/content/weblog/2019-01-11_intro-to-linux-and-bash-pt3/index.ru.md
blob: 983805f3c5bb85856bb1217277dc7700622f1b5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
+++
title = "Введение в Linux и Bash, часть III"
date = 2019-01-11T08:23:00Z
+++

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

<!-- more -->

## Фильтры

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

### cat

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

```sh
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'

```sh
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 чтобы показать номер строки

```sh
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').

### head

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

```sh
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, но в отличие от нее, данная команда показывает
последние строки текста. Допустим мы хотим увидеть последние три строки

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

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

### sort

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

```sh
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

```sh
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/<search>/<replace>/2')
она заменит только вторые совпадения в каждой строке.

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

```sh
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) мемы

```sh
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

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

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

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

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

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

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

```sh
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", затем чтобы включить расширенные
регулярные выражения. Например

```sh
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' в качестве
последнего символа в строке

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

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

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

```sh
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'а для
поиска и замены, только в нашем случае мы хотим заменить комментарии на
пустоту. Затем нам понадобится вставить регулярное выражение, которое поможет
нам найти комментарии - '#.*'. Этот шаблон переводится как - найди символ '#' и
все что после него находится. А теперь давайте мы все совместим

```sh
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), и так...

```sh
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'а '>' и '>>'. Первый оператор переписывает файл,
если указанный файл уже существует, а второй просто добавляет поток текста в
конец файла. В этом случае безразлично какой из этих операторов использовать,
ибо мы хотим записать поток текста на новый файл

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

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

### Конвейер

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

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

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

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

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

```sh
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), но есть и
другие форматы сжатия.

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

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

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

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

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

### ssh and scp

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

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

```sh
user@host:~$ ssh tux@180.80.8.20
```

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

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

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

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

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

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


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