КулЛиб - Классная библиотека! Скачать книги бесплатно 

Linux. Командная строка [Дэниел Джей Барретт] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]
Beijing

Boston Farnham Sebastopol

Tokyo

Linux
Командная строка
Лучшие практики

Дэниел Джей Барретт

2023

ББК 32.973.2-018.2
УДК 004.451
Б25

Барретт Дэниел Джей
Б25

 inux. Командная строка. Лучшие практики. — СПб.: Питер, 2023. — 256 с.: ил. —
L
(Серия «Бестселлеры O’Reilly»).
ISBN 978-5-4461-2300-1
Перейдите на новый уровень работы в Linux! Если вы системный администратор, разработчик
программного обеспечения, SRE-инженер или пользователь Linux, книга поможет вам работать
быстрее, элегантнее и эффективнее. Вы научитесь создавать и запускать сложные команды,
которые решают реальные бизнес-задачи, обрабатывать и извлекать информацию, а также автоматизировать ручную работу.
Узнайте, что происходит внутри командной оболочки Linux. Вне зависимости от используемых команд вы повысите эффективность работы в Linux и станете более конкурентоспособным
специалистом.

16+ (В соответствии с Федеральным законом от 29 декабря 2010 г. № 436-ФЗ.)

ББК 32.973.2-018.2
УДК 004.451
Права на издание получены по соглашению с O’Reilly.
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было
форме без письменного разрешения владельцев авторских прав.
Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как
надежные. Тем не менее, имея в виду возможные человеческие или технические ошибки, издательство не
может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности
за возможные ошибки, связанные с использованием книги.
В книге возможны упоминания организаций, деятельность которых запрещена на территории Российской
Федерации, таких как Meta Platforms Inc., Facebook, Instagram и др.
Издательство не несет ответственности за доступность материалов, ссылки на которые вы можете найти
в этой книге. На момент подготовки книги к изданию все ссылки на интернет-ресурсы были действующими.

ISBN 978-1098113407 англ.

ISBN 978-5-4461-2300-1

 uthorized Russian translation of the English edition of Efficient Linux at the
A
Command Line, ISBN 9781098113407 © 2022 Daniel Barrett.
This translation is published and sold by permission of O’Reilly Media, Inc.,
which owns or controls all rights to publish and sell the same.
© Перевод на русский язык ООО «Прогресс книга», 2022
© Издание на русском языке, оформление ООО «Прогресс книга», 2023
© Серия «Бестселлеры O’Reilly», 2023

Оглавление
Предисловие............................................................................................................10
Чему вы научитесь........................................................................................................................11
Чем эта книга не является.........................................................................................................11
Для кого эта книга.........................................................................................................................12
Ваша командная оболочка........................................................................................................13
Условные обозначения...............................................................................................................13
Использование исходного кода примеров.......................................................................14
Благодарности.........................................................................................................15
От издательства.......................................................................................................16

ЧАСТЬ 1
ОСНОВНЫЕ ПОНЯТИЯ
Глава 1. Объединение команд...............................................................................18
Ввод, вывод и каналы..................................................................................................................19
Шесть команд для начала..........................................................................................................21
Команда #1: wc.........................................................................................................................21
Команда #2: head.....................................................................................................................24
Команда #3: cut........................................................................................................................24
Команда #4: grep.....................................................................................................................26
Команда #5: sort.......................................................................................................................28
Команда #6: uniq.....................................................................................................................30
Обнаружение дубликатов файлов.........................................................................................32
Резюме................................................................................................................................................34
Глава 2. Знакомство с командной оболочкой.....................................................35
Терминология командной оболочки...................................................................................36
Сопоставление шаблонов имен файлов.............................................................................37
Вычисление переменных..........................................................................................................40
Откуда берутся значения переменных........................................................................40
Переменные и заблуждения.............................................................................................41
Шаблоны vs переменные....................................................................................................42
Сокращение команд с помощью псевдонимов...............................................................43
Перенаправление ввода и вывода........................................................................................44
Отключение вычисления с помощью кавычек и экранирования..........................47

6   Оглавление

Расположение исполняемых программ.............................................................................49
Окружение и файлы инициализации, краткая версия.................................................50
Резюме................................................................................................................................................52
Глава 3. Повторный запуск команд......................................................................53
Просмотр истории команд.......................................................................................................54
Повторный вызов команд из истории.................................................................................55
Перемещение курсора по истории команд...............................................................55
Расширение истории команд............................................................................................57
Забудьте об ошибочном удалении файлов
(спасибо расширению истории)......................................................................................60
Инкрементальный поиск по истории команд...........................................................62
Редактирование командной строки.....................................................................................64
Перемещение курсора внутри команды.....................................................................65
Расширение истории с помощью знака вставки.....................................................65
Редактирование командной строки в стилях Emacs или Vim............................67
Резюме................................................................................................................................................69
Глава 4. Перемещение по файловой системе.....................................................70
Лучшие способы перехода в нужный каталог.................................................................71
Переход в домашний каталог...........................................................................................71
Перемещайтесь быстрее с автозавершением командной строки..................72
Переход к часто посещаемым каталогам с использованием
псевдонимов или переменных........................................................................................73
Уменьшите пространство поиска с помощью CDPATH.........................................75
Организуйте свой домашний каталог для быстрой навигации........................77
Лучшие способы вернуться в каталог.................................................................................79
Переключение между двумя каталогами с помощью «cd -»...............................79
Переключение между несколькими каталогами
с помощью pushd и popd....................................................................................................80
Резюме................................................................................................................................................86

ЧАСТЬ 2
ПРОДВИНУТЫЕ НАВЫКИ
Глава 5. Расширяем ваш инструментарий...........................................................88
Создание текста.............................................................................................................................89
Команда date.............................................................................................................................89
Команда seq...............................................................................................................................90
Расширение команд с помощью фигурных скобок................................................91
Команда find..............................................................................................................................93

Оглавление  

7

Команда yes...............................................................................................................................94
Извлечение текста........................................................................................................................95
Команда grep. Более глубокий взгляд...........................................................................96
Команда tail............................................................................................................................ 100
Команда awk {print} ............................................................................................................ 101
Объединение текста................................................................................................................. 103
Команда tac............................................................................................................................ 104
Команда paste........................................................................................................................ 104
Команда diff............................................................................................................................ 105
Преобразование текста........................................................................................................... 106
Команда tr............................................................................................................................... 107
Команда rev............................................................................................................................ 107
Команды awk и sed.............................................................................................................. 108
Как расширить инструментарий......................................................................................... 117
Резюме............................................................................................................................................. 119
Глава 6. Родители, потомки и окружение......................................................... 120
Оболочки — это исполняемые файлы............................................................................. 121
Родительский и дочерний процессы................................................................................ 123
Переменные окружения......................................................................................................... 125
Создание переменных окружения.............................................................................. 126
Предупреждение о мифе: «глобальные» переменные...................................... 127
Дочерние оболочки vs подоболочки................................................................................ 128
Настройка окружения.............................................................................................................. 129
Повторное считывание файла конфигурации....................................................... 132
Путешествие с вашим окружением............................................................................. 132
Резюме............................................................................................................................................. 133
Глава 7. Еще 11 способов запуска команды..................................................... 134
Способы, использующие списки......................................................................................... 134
Способ #1. Условные списки........................................................................................... 135
Способ #2. Безусловные списки................................................................................... 137
Способы, использующие подстановку............................................................................. 137
Способ #3. Подстановка команд................................................................................... 138
Способ #4. Подстановка процесса............................................................................... 140
Команда как строка................................................................................................................... 143
Способ #5. Передача команды в bash в качестве аргумента........................... 144
Способ #6. Передача команды в bash через стандартный ввод.................... 145
Способ #7. Удаленное выполнение однострочника с помощью ssh........... 147
Способ #8. Запуск списка команд с помощью xargs............................................ 148

8   Оглавление

Способы, использующие управление процессами.................................................... 153
Способ #9. Фоновое выполнение команды............................................................. 153
Способ #10. Явные подоболочки................................................................................. 159
Способ #11. Замена процесса........................................................................................ 161
Резюме............................................................................................................................................. 162
Глава 8. Создание дерзких однострочников.................................................... 164
Приготовьтесь быть дерзкими............................................................................................. 166
Будьте гибкими..................................................................................................................... 166
Подумайте, с чего начать................................................................................................. 167
Изучите инструменты тестирования.......................................................................... 169
Вставка имени файла в последовательность................................................................ 169
Проверка совпадающих пар файлов................................................................................. 172
Создание CDPATH из вашего домашнего каталога..................................................... 175
Создание тестовых файлов.................................................................................................... 177
Создание пустых файлов........................................................................................................ 180
Резюме............................................................................................................................................. 181
Глава 9. Использование текстовых файлов..................................................... 182
Первый пример: поиск файлов............................................................................................ 184
Проверка срока действия домена...................................................................................... 185
Создание базы данных телефонных кодов.................................................................... 188
Создание менеджера паролей............................................................................................. 190
Резюме............................................................................................................................................. 197

ЧАСТЬ 3
ДОПОЛНИТЕЛЬНЫЕ ПЛЮСЫ
Глава 10. Эффективное использование клавиатуры..................................... 200
Работа с окнами........................................................................................................................... 200
Мгновенный запуск оболочек и браузера............................................................... 201
Одноразовые окна.............................................................................................................. 202
Горячие клавиши в браузере......................................................................................... 202
Переключение окон и рабочих столов..................................................................... 203
Доступ в интернет из командной строки........................................................................ 204
Запуск окон браузера из командной строки.......................................................... 204
Получение HTML-страниц с помощью curl и wget............................................... 207
Обработка кода HTML с помощью HTML-XML-utils.............................................. 208
Получение и отображение содержимого веб-сайтов с помощью
текстового браузера.......................................................................................................... 212

Оглавление  

9

Управление буфером обмена из командной строки................................................. 213
Подключение буферов обмена к stdin и stdout..................................................... 214
Улучшение работы менеджера паролей.................................................................. 216
Резюме............................................................................................................................................. 219
Глава 11. Финальные советы по экономии времени...................................... 220
Способы решения задач легко и быстро......................................................................... 220
Переход в текстовый редактор напрямую из команды less............................ 220
Редактирование файлов, содержащих заданную строку................................. 221
Смиритесь с опечатками.................................................................................................. 222
Быстрое создание пустых файлов............................................................................... 222
Обработка файла построчно.......................................................................................... 223
Список команд, поддерживающих рекурсию........................................................ 223
Читайте справочные страницы..................................................................................... 224
Способы решения задач, требующие затрат времени на изучение................... 224
Прочтите справочную страницу команды bash.................................................... 224
Изучите команды cron, crontab и at............................................................................. 225
Изучите команду rsync...................................................................................................... 226
Изучите другой язык для написания сценариев................................................... 227
Используйте make для задач, не связанных с программированием........... 228
Применяйте контроль версий к повседневным файлам.................................. 230
Прощание...................................................................................................................................... 231
Приложение A. Памятка по Linux....................................................................... 233
Команды, аргументы и параметры..................................................................................... 233
Файловая система, каталоги и пути................................................................................... 234
Перемещение по каталогам.................................................................................................. 236
Создание и редактирование файлов................................................................................ 236
Работа с файлами и каталогами........................................................................................... 237
Просмотр файлов....................................................................................................................... 239
Права доступа к файлам.......................................................................................................... 239
Процессы........................................................................................................................................ 240
Просмотр документации........................................................................................................ 241
Сценарии оболочки.................................................................................................................. 242
Получение привилегий суперпользователя................................................................. 243
Дополнительная литература................................................................................................ 244
Приложение Б. Если вы используете не bash................................................... 245
Об авторе............................................................................................................... 251
Иллюстрация на обложке.................................................................................... 252

Предисловие

Эта книга позволит перейти на новый уровень использования командной строки
Linux, чтобы вы могли работать быстрее, умнее и эффективнее.
Если вы похожи на большинство пользователей Linux, то приобрели первоначальные навыки использования командной строки на работе, или прочитав
вводную книгу, или установив Linux дома и просто попробовав. Моя книга
должна помочь вам сделать следующий шаг — развить навыки работы с командной строкой Linux от среднего до продвинутого уровня. Она наполнена
методами и концепциями, которые, я надеюсь, изменят ваше взаимодействие
с Linux и повысят производительность. Воспринимайте ее как вторую книгу по
использованию Linux, которая выведет вас за рамки азов.
Командная строка — самый простой и вместе с тем самый сложный из интерфейсов. Он прост, потому что содержит только приглашение командной строки,
которое ждет ваших действий1:
$

Он сложный, потому что за все, что выходит за рамки приглашения, отвечаете
только вы. Нет понятных значков, кнопок или меню, которые могли бы помочь.
Вместо этого каждая введенная команда является результатом ваших усилий.
Это верно как для основных команд, таких, например, как вывод списка файлов:
$ ls

так и для более сложных, например:
$ paste 1 {print $4}'
890244772
5466214400

Объединение текста  

103

Если вы столкнулись с вводом, разделенным чем-то другим, кроме пробелов,
awk с параметром -F может изменить разделитель полей на любое регулярное
выражение:
$ echo efficient:::::linux | awk -F':*' '{print $2}'
linux

Любое количество двоеточий

Вы узнаете больше о команде awk в разделе «Основы awk» на с. 109.

Объединение текста
Вы уже знаете несколько команд, объединяющих текст из разных файлов.
Первая — это cat, которая выводит содержимое нескольких файлов. Это последовательное объединение текстов «сверху вниз». Отсюда и его название — он
объединяет (concatenates) файлы:
$ cat poem1
It is an ancient Mariner,
And he stoppeth one of three.
$ cat poem2
'By thy long grey beard and glittering eye,
$ cat poem3
Now wherefore stopp'st thou me?
$ cat poem1 poem2 poem3
It is an ancient Mariner,
And he stoppeth one of three.
'By thy long grey beard and glittering eye,
Now wherefore stopp'st thou me?

Вторая команда для объединения текста, которую вы видели, — это встроенная
в оболочку echo. Она печатает любые переданные вами аргументы, разделяя их
одним пробелом, и соединяет тексты в одну строку:
$ echo efficient linux in $HOME
efficient linux in /home/smith

Давайте рассмотрим еще несколько команд, объединяющих текст:
tac — последовательное объединение текстовых файлов.
paste — объединение строк текстовых файлов.
diff — команда, которая чередует текст из двух файлов, отображая только их
различия.

104  Глава 5. Расширяем ваш инструментарий

Команда tac
Команда tac построчно переворачивает каждый текст. Ее имя — это написанное
задом наперед название команды cat.
$ cat poem1 poem2 poem3 | tac
Now wherefore stopp'st thou me?
'By thy long grey beard and glittering eye,
And he stoppeth one of three.
It is an ancient Mariner,

Обратите внимание, что три файла были объединены, прежде чем перевернуть
текст. Если вместо этого указать команде tac несколько файлов в качестве аргументов, она перевернет строки каждого файла по очереди, выведя на экран
другие данные:
$ tac poem1 poem2 poem3
And he stoppeth one of three.
It is an ancient Mariner,
'By thy long grey beard and glittering eye,
Now wherefore stopp'st thou me?

Первый файл перевернут
Второй файл
Третий файл

tac отлично подходит для обработки данных, которые уже находятся в определенном порядке, но не могут быть отсортированы с помощью команды sort -r.

Типичным случаем является преобразование файла журнала веб-сервера для
обработки его строк от самых новых к самым старым:
192.168.1.34 - - [30/Nov/2021:23:37:39 -0500] "GET / HTTP/1.1" ...
192.168.1.10 - - [01/Dec/2021:00:02:11 -0500] "GET /notes.html HTTP/1.1" ...
192.168.1.8 - - [01/Dec/2021:00:04:30 -0500] "GET /stuff.html HTTP/1.1" ...


Строки расположены в хронологическом порядке с отметками времени, но не
в алфавитном или числовом порядке, поэтому команда sort -r бесполезна. Команда tac может перевернуть эти строки, не обращая внимания на метки времени.

Команда paste
Команда paste объединяет строки текстов в столбцы, разделенные одним
символом табуляции. Это сестра команды cut, которая извлекает разделенные
табуляцией столбцы из текста:
$ cat title-words1
EFFICIENT
AT
COMMAND

Объединение текста  

$ cat title-words2
linux
the
line
$ paste title-words1 title-words2
EFFICIENT
linux
AT the
COMMAND line
$ paste title-words1 title-words2 | cut -f2
linux
the
line

105

cut и paste дополняют друг друга

Измените разделитель на другой символ, например запятую, с помощью параметра -d (delimiter):
$ paste -d, title-words1 title-words2
EFFICIENT,linux
AT,the
COMMAND,line

Измените вывод, поменяв последовательность объединения с помощью параметра -s:
$ paste -d, -s title-words1 title-words2
EFFICIENT,AT,COMMAND
linux,the,line

Команда paste также может чередовать строки из двух или более файлов, если
вы измените разделитель на символ новой строки (\n):
$ paste -d "\n" title-words1 title-words2
EFFICIENT
linux
AT
the
COMMAND
line

Команда diff
Команда diff сравнивает два файла построчно и выводит краткий отчет об их
различиях:
$ cat file1
Linux is all about efficiency.
I hope you will enjoy this book.
$ cat file2
MacOS is all about efficiency.

106  Глава 5. Расширяем ваш инструментарий

I hope you will enjoy this book.
Have a nice day.
$ diff file1 file2
1c1
< Linux is all about efficiency.
--> MacOS is all about efficiency.
2a3
> Have a nice day.

Код 1c1 означает, что строка 1 в первом файле отличается от строки 1 во втором
файле. За этим кодом следует соответствующая строка из file1, разделитель из
трех дефисов (---) и соответствующая строка из file2. Начальный символ < всегда
указывает на строку из первого файла, а > указывает на строку из второго файла.
Код 2a3 означает, что в файле file2 есть третья строка, отсутствующая после
второй строки файла file1. За этим обозначением следует дополнительная строка
из файла 2: Have a nice day.
Вывод diff может содержать другие обозначения и принимать другие формы.
Однако этого краткого объяснения достаточно для нашей основной цели — использования diff для чередования строк из двух файлов. Многие пользователи
не думали о таком применении diff, но эта команда отлично подходит для
формирования конвейеров при решении определенных задач. Например, вы
можете вывести разные строки с помощью diff, grep и cut:
$ diff file1 file2 | grep '^[]'
< Linux is all about efficiency.
> MacOS is all about efficiency.
> Have a nice day.
$ diff file1 file2 | grep '^[]' | cut -c3Linux is all about efficiency.
MacOS is all about efficiency.
Have a nice day.

Практические примеры приведены в разделах «Способ #4: Подстановка процесса» на с. 140 и «Проверка совпадающих пар файлов» на с. 172.

Преобразование текста
В главе 1 было представлено несколько команд, которые считывают текст со
стандартного ввода и преобразуют его в стандартном выходе. Команда wc выводит
количество строк, слов и символов; sort упорядочивает строки в алфавитном
или числовом порядках; а uniq объединяет повторяющиеся строки. Давайте
обсудим еще несколько команд, которые преобразуют ввод:

Преобразование текста  

107

tr — преобразует одни символы в другие.
rev — переворачивает символы в строке задом наперед.
awk и sed — преобразователи текста общего назначения.

Команда tr
Команда tr переводит один набор символов в другой. В главе 2 мы видели пример
преобразования двоеточий в символы новой строки для вывода переменной PATH:
$ echo $PATH | tr : "\n"
Преобразование двоеточий в символы новой
/home/smith/bin строки
/usr/local/bin
/usr/bin
/bin
/usr/games
/usr/lib/java/bin

tr принимает два набора символов в качестве аргументов и переводит элементы

первого набора в соответствующие элементы второго. Часто выполняется преобразование текста в верхний или нижний регистр:
$ echo efficient | tr a-z A-Z
EFFICIENT
$ echo Efficient | tr A-Z a-z
efficient

Перевод a в A, b в B и т. д.

Преобразование пробелов в символы новой строки:
$ echo Efficient Linux | tr " " "\n"
Efficient
Linux

Удаление пробелов с помощью параметра -d:
$ echo efficient linux | tr -d ' \t'
efficientlinux

Удаление пробелов и знаков табуляции

Команда rev
Команда rev переворачивает символы задом наперед в каждой строке ввода1:
$ echo Efficient Linux! | rev
!xuniL tneiciffE
1

Вопрос к читателям: что делает конвейер rev myfile | tac | rev | tac ?

108  Глава 5. Расширяем ваш инструментарий

Помимо очевидной развлекательной ценности, rev удобна для извлечения
сложной информации из файлов. Предположим, у вас есть файл с именами
знаменитостей:
$ cat celebrities
Jamie Lee Curtis
Zooey Deschanel
Zendaya Maree Stoermer Coleman
Rihanna

и вы хотите вывести на экран последнее слово из каждой строки (Curtis,
Deschanel, Coleman, Rihanna). Это было бы легко сделать с помощью команды
cut -f, если бы в каждой строке было одинаковое количество полей, но это
число различается. С помощью rev вы можете перевернуть все строки, вырезать
первое слово и снова перевернуть, чтобы добиться желаемого:
$ rev celebrities
sitruC eeL eimaJ
lenahcseD yeooZ
nameloC remreotS eeraM ayadneZ
annahiR
$ rev celebrities | cut -d' ' -f1
sitruC
lenahcseD
nameloC
annahiR
$ rev celebrities | cut -d' ' -f1 | rev
Curtis
Deschanel
Coleman
Rihanna

Команды awk и sed
awk и sed — это универсальные «суперкоманды» для обработки текста. Они по-

зволяют решать практически все задачи, которые рассматривались ранее в этой
главе, но с помощью более сложного синтаксиса. Например, они могут вывести
первые 10 строк файла, как это делает head:
$ sed 10q myfile
Выводит 10 строк и завершается
$ awk 'FNR5
указывает awk пропустить первые пять строк ввода.
Действие без шаблона выполняется для каждой строки ввода (несколько awkпрограмм в разделе «Команда awk {print}» на с. 101 относятся к этому типу).
Например, awk элегантно решает задачу «напечатать фамилию знаменитости»
из примера в разделе «Команды rev» на с. 107, напрямую печатая последнее
слово из каждой строки:
$ awk '{print $NF}' celebrities
Curtis
Deschanel
Coleman
Rihanna

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

Шаблон без указания действия запускает действие по умолчанию {print},
которое просто печатает любые совпадающие входные строки без изменений:
$ echo efficient linux | awk '/efficient/'
efficient linux

Для более полной демонстрации давайте обработаем разделенный табуляцией
текст файла animals.txt из примера 1.1 на с. 21, чтобы создать аккуратную библиографию. Необходимо преобразовать строки вида
python Programming Python 2010 Lutz, Mark

в следующий формат:
Lutz, Mark (2010). "Programming Python"

Преобразование текста  

111

Необходима перестановка трех полей и добавление некоторых символов, таких
как круглые скобки и двойные кавычки. Следующая awk-программа выполняет
это, используя параметр -F для изменения разделителя ввода с пробелов на
табуляцию (\t):
$ awk -F'\t' '{print $4, "(" $3 ").", "\"" $2 "\""}' animals.txt
Lutz, Mark (2010). "Programming Python"
Barrett, Daniel (2005). "SSH, The Secure Shell"
Schwartz, Randal (2012). "Intermediate Perl"
Bell, Charles (2014). "MySQL High Availability"
Siever, Ellen (2009). "Linux in a Nutshell"
Boney, James (2005). "Cisco IOS in a Nutshell"
Roman, Steven (1999). "Writing Word Macros"

Добавим регулярное выражение для обработки только названия книги, содержащего horse:
$ awk -F'\t' ' /^horse/ {print $4, "(" $3 ").", "\"" $2 "\""}' animals.txt
Siever, Ellen (2009). "Linux in a Nutshell"

Или отберем только книги, изданные не раньше 2010 года, проверив, соответствует ли поле $3 шаблону ^201:
$ awk -F'\t' ' $3~/^201/ {print $4, "(" $3 ").", "\"" $2 "\""}' animals.txt
Lutz, Mark (2010). "Programming Python"
Schwartz, Randal (2012). "Intermediate Perl"
Bell, Charles (2014). "MySQL High Availability"

Наконец, добавим инструкцию BEGIN, чтобы напечатать понятный заголовок,
дефисы для отступов и инструкцию END, чтобы направить читателя к дополнительной информации:
$ awk -F'\t' \
' BEGIN {print "Recent books:"} \
$3~/^201/{print "-", $4, "(" $3 ").", "\"" $2 "\""} \
END {print "For more books, search the web"} ' \
animals.txt
Recent books:
- Lutz, Mark (2010). "Programming Python"
- Schwartz, Randal (2012). "Intermediate Perl"
- Bell, Charles (2014). "MySQL High Availability"
For more books, search the web

Команда awk умеет гораздо больше, чем просто вывод данных — она также может
выполнять вычисления, например суммировать числа от 1 до 100:
$ seq 1 100 | awk '{s+=$1} END {print s}'
5050

112  Глава 5. Расширяем ваш инструментарий

Чтобы изучить awk, воспользуйтесь учебными пособиями на tutorialspoint.com/
awk или riptutorial.com/awk либо выполните поиск в интернете по запросу awk
tutorial. Результат вам понравится.

Улучшенный способ обнаружения дубликатов файлов
В разделе «Обнаружение дубликатов файлов» на с. 32 вы построили конвейер,
который обнаруживает и подсчитывает дубликаты файлов JPEG по контрольной
сумме, но его возможностей не хватает для вывода имен файлов:
$ md5sum *.jpg | cut -c1-32 | sort | uniq -c | sort -nr | grep -v "
3 f6464ed766daca87ba407aede21c8fcc
2 c7978522c58425f6af3f095ef1de1cd5
2 146b163929b6533f02e91bdf21cb9563

1 "

Теперь, когда мы знаем команду awk, у нас также есть инструменты для печати
имен файлов. Давайте создадим новую команду, которая считывает каждую
строку вывода md5sum:
$ md5sum *.jpg
146b163929b6533f02e91bdf21cb9563 image001.jpg
63da88b3ddde0843c94269638dfa6958 image002.jpg
146b163929b6533f02e91bdf21cb9563 image003.jpg


но не только подсчитывает вхождения каждой контрольной суммы, но и сохраняет имена файлов для вывода на экран. Нам понадобятся две дополнительные
возможности команды awk — массивы и циклы.
Массив — это переменная, содержащая набор значений. Если массив называется
A и содержит семь значений, то к ним можно обращаться через элементы массива
A[1], A[2], A[3], вплоть до A[7]. Значения от 1 до 7 называются ключами массива.
Вы можете создать любые ключи, какие захотите. Если вы предпочитаете обращаться к элементам массива, используя имена персонажей Диснея, назовите
их A["Doc"], A["Grumpy"], A["Bashful"], вплоть до A ["Dopey"].
Чтобы подсчитать повторяющиеся изображения, создадим массив counts с одним
элементом для каждой контрольной суммы. Каждый ключ массива представляет
собой контрольную сумму, а связанный с ним элемент содержит количество раз,
которое контрольная сумма встречается во входных данных. Например, элемент
массива counts["f6464ed766daca87ba407aede21c8fcc"] может иметь значение 3.
Следующий сценарий команды awk проверяет каждую строку вывода md5sum,
выделяет контрольную сумму ($1) и использует ее в качестве ключа для массива

Преобразование текста  

113

counts. Оператор ++ увеличивает элемент на 1 каждый раз, когда awk встречает

связанную с ним контрольную сумму:
$ md5sum *.jpg | awk '{counts[$1]++}'

Пока что awk-программа ничего не выводит, она просто обрабатывает каждую
контрольную сумму и завершает работу. Чтобы вывести на экран количество
посчитанных значений, нам понадобится вторая функция awk , называемая
циклом for. Цикл for проходит по всем ключам массива и последовательно
обрабатывает каждый его элемент. Например, следующая команда выводит
значения элементов массива counts по их ключам:
for (key in counts) print counts[key]

Поместим этот цикл в инструкцию END, чтобы он выполнялся после вычисления
всех элементов массива:
$ md5sum *.jpg \
| awk '{counts[$1]++} \
END { for (key in counts) print counts[key] }'
1
2
2


Затем добавим контрольные суммы в вывод. Каждый ключ массива является
контрольной суммой, поэтому просто выведем их:
$ md5sum *.jpg \
| awk '{counts[$1]++} \
END {for (key in counts) print counts[key] " " key }'
1 714eceeb06b43c03fe20eb96474f69b8
2 146b163929b6533f02e91bdf21cb9563
2 c7978522c58425f6af3f095ef1de1cd5


Для сбора и вывода имен файлов используем массив names также с контрольными
суммами в качестве ключей. Так как awk обрабатывает каждую строку вывода,
добавим имя файла ($2) к соответствующему элементу массива имен вместе
с пробелом в качестве разделителя. В цикле END после печати контрольной суммы
(key) выведем двоеточие и собранные имена файлов для этой контрольной суммы:
$ md5sum *.jpg \
| awk '{counts[$1]++; names[$1]=names[$1] " " $2 } \
END {for (key in counts) print counts[key] " " key ":" names[key] }'
1 714eceeb06b43c03fe20eb96474f69b8: image011.jpg
2 146b163929b6533f02e91bdf21cb9563: image001.jpg image003.jpg
2 c7978522c58425f6af3f095ef1de1cd5: image019.jpg image020.jpg


114  Глава 5. Расширяем ваш инструментарий

Строки, начинающиеся с единицы, представляют собой контрольные суммы,
которые встречаются только один раз, то есть не дублируются. Направим вывод
в grep -v, чтобы удалить эти строки, затем отсортируем результаты от большего
к меньшему с помощью sort -nr — и получим желаемый результат:
$ md5sum *.jpg \
| awk '{counts[$1]++; names[$1]=names[$1] " " $2} \
END {for (key in counts) print counts[key] " " key ":" names[key]}' \
| grep -v '^1 ' \
| sort -nr
3 f6464ed766daca87ba407aede21c8fcc: image007.jpg image012.jpg image014.jpg
2 c7978522c58425f6af3f095ef1de1cd5: image019.jpg image020.jpg
2 146b163929b6533f02e91bdf21cb9563: image001.jpg image003.jpg

Основы sed
Команда sed преобразует текст из файлов или из стандартного ввода, используя
последовательность инструкций, которую называют sed-сценарием1. Сценарии
sed на первый взгляд малопонятны. Примером может служить s/Windows/Linux/g,
заменяющий каждое вхождение строки Windows на Linux. Термин сценарий
в данном случае означает не файл (например, сценарий оболочки), а строку2.
Вызовите сценарий sed в командной строке:
$ sed script input-files

или используйте параметр -e для поддержки нескольких сценариев, которые
последовательно обрабатывают ввод:
$ sed -e script1 -e script2 -e script3 input-files

Также можно хранить sed-сценарии в файлах и обращаться к ним с параметром
-f, тогда они будут запускаться последовательно:
$ sed -f script-file1 -f script-file2 -f script-file3 input-files

Как и в случае с awk, преимущества использования sed зависят от вашего умения
создавать сценарии. Наиболее часто используемым сценарием является подстановка, которая заменяет одни строки другими. Ее синтаксис:
s/regexp/replacement/

1

2

Название команды sed является сокращением от stream editor, потому что она редактирует
текстовый поток.
Если вы знакомы с редакторами vi, vim, ex или ed, синтаксис сценария sed может показаться вам знакомым.

Преобразование текста  

115

где regexp — регулярное выражение для сопоставления с каждой входной строкой
(см. табл. 5.1); replacement — строка для замены совпадающего текста. В качестве
простого примера замена слов:
$ echo Efficient Windows | sed "s/Windows/Linux/"
Efficient Linux

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

sed легко решает задачу вывода фамилии знаменитости из раздела «Команда rev»

на с. 107 с помощью регулярного выражения. Просто сопоставьте все символы
(.*) до последнего пробела и ничем их не заменяйте:
$ sed 's/.* //' celebrities
Curtis
Deschanel
Coleman
Rihanna

Подстановка и символ слеша
Косая черта в подстановке может быть заменена любым другим удобным
символом. Это полезно, когда само регулярное выражение включает слеш,
который в противном случае пришлось бы экранировать. Следующие три
сценария sed эквивалентны:
s/one/two/
s_one_two_
s@one@two@

В сценарии после подстановки могут следовать несколько параметров, влияющих на результат. Например, параметр i делает совпадения нечувствительными
к регистру:
$ echo Efficient Stuff | sed "s/stuff/linux/" Чувствительно к регистру. Нет
совпадений
Efficient Stuff
$ echo Efficient Stuff | sed "s/stuff/linux/i"
Нечувствительно к регистру
Efficient linux

116  Глава 5. Расширяем ваш инструментарий

Параметр g (global) заменяет все вхождения регулярного выражения, а не только
первое:
$ echo efficient stuff | sed "s/f/F/"
eFficient stuff
$ echo efficient stuff | sed "s/f/F/g"
eFFicient stuFF

Заменяет только первую «f»
Заменяет все вхождения «f»

Другим распространенным типом sed-сценария является удаление. Сценарий,
удаляющий строки по их номеру:
$ seq 10 14 | sed 4d Удаляет четвертую строку
10
11
12
14

Сценарий, удаляющий строки, которые соответствуют регулярному выражению:
$ seq 101 200 | sed '/[13579]$/d'
Удаляет строки, заканчивающиеся
на нечетные цифры
102
104
106

200

Сопоставление подвыражений с sed
Предположим, у нас есть несколько имен файлов:
$ ls
image.jpg.1 image.jpg.2 image.jpg.3

и мы хотим создать новые имена, image1.jpg, image2.jpg и image3.jpg. sed может
разбить имена файлов на части и изменить их порядок с помощью функции,
называемой подвыражениями. Сначала создадим регулярное выражение, соответствующее именам файлов:
image\.jpg\.[1-3]

Чтобы переместить последнюю цифру в имени файла на другую позицию, изолируем ее, окружив символами \( и \). Это определяет подвыражение — выделенную часть регулярного выражения:
image\.jpg\. \( [1-3] \)

sed может ссылаться на подвыражения по номеру и управлять ими. Мы создали
только одно подвыражение, поэтому его имя \1. Вторым подвыражением будет

Как расширить инструментарий  

117

\2 и т. д., максимум — \9. Новые имена файлов будут иметь вид image\1.jpg.

Следовательно, sed-сценарий будет таким:

$ ls | sed "s/image\.jpg\.\([1-3]\)/image\1.jpg/"
image1.jpg
image2.jpg
image3.jpg

Чтобы усложнить ситуацию, предположим, что имена файлов имеют больше
отличий и состоят из слов нижнего регистра:
$ ls
apple.jpg.1 banana.png.2 carrot.jpg.3

Создадим три подвыражения для захвата начального имени файла, расширения
и последней цифры:
\([a-z][a-z]*\)
\([a-z][a-z][a-z]\)
\([0-9]\)

\1 = Начальное имя файла из одной буквы или более
\2 = Расширение файла из трех букв
\3 = Цифра

Соединим их с помощью экранированных точек (\.), чтобы сформировать
следующее регулярное выражение:
\([a-z][a-z]*\) \. \([a-z][a-z][a-z]\) \. \([0-9]\)

Преобразуем имена файлов в формате sed как \1\3.\2, тогда окончательный
сценарий будет выглядеть так:
$ ls | sed "s/\([a-z][a-z]*\)\.\([a-z][a-z][a-z]\)\.\([0-9]\)/\1\3.\2/"
apple1.jpg
banana2.png
carrot3.jpg

Эта команда не переименовывает файлы, она просто выводит на экран новые
имена. В разделе «Вставка имени файла в последовательность» на с. 169 показан
аналогичный пример, в котором также выполняется переименование.
Чтобы изучить sed, воспользуйтесь учебниками https://tutorialspoint.com/sed или
https://grymoire.com/Unix/Sed.html либо выполните поиск в интернете по запросу
sed tutorial.

Как расширить инструментарий
Большинство систем Linux поставляются с тысячами программ командной
строки, и большинство из них имеют множество параметров, изменяющих их

118  Глава 5. Расширяем ваш инструментарий

поведение. Вы вряд ли это все выучите и запомните. Отсюда возникает вопрос:
как найти нужную программу или адаптировать другую, которую вы уже знаете,
для достижения своих целей?
Первый и самый очевидный шаг — поиск в интернете. Например, если вам нужна команда, которая ограничивает ширину строк в текстовом файле, перенося
слишком длинные строки, поищите по фразе «перенос строк команд Linux»
(«Linux command wrap lines») — и вы увидите команду fold :
$ cat title.txt
This book is titled "Efficient Linux at the Command Line"
$ fold -w40 title.txt
This book is titled "Efficient Linux at
the Command Line"

Чтобы найти команды, которые уже установлены в вашей системе Linux, запустите man -k (или, что то же самое, команду apropos). Получив слово, man -k
ищет его в кратких описаниях справочных страниц:
$ man -k width
DisplayWidth (3) - image format functions and macros
DisplayWidthMM (3) - image format functions and macros
fold (1) - wrap each input line to fit in specified width


man -k работает с регулярными выражениями в стиле awk в строках поиска (см.

таблицу 5.1):

$ man -k "wide|width"

Команда, которая отсутствует в вашей системе, может быть установлена через
менеджер пакетов вашей версии Linux. Менеджер пакетов — это программное
обеспечение для установки программ Linux, которые поддерживаются вашей
системой. Популярными менеджерами пакетов являются apt, dnf, emerge, pacman,
rpm, yum и zypper. Используйте команду man, чтобы выяснить, какой менеджер
пакетов установлен в вашей системе, и узнайте, как искать неустановленные
пакеты. Часто требуется последовательность из двух команд: первой — для копирования последних данных о доступных пакетах (метаданных) из интернета
в вашу систему, второй — для поиска метаданных. Например, для систем на базе
Ubuntu или Debian Linux команды следующие:
$ sudo apt update Скачать новейшие метаданные
$ apt-file search string
Искать строку string

Если после долгих поисков вы не нашли команду, отвечающую вашим задачам,
обратитесь за помощью на онлайн-форум. Отличной отправной точкой, чтобы
задавать правильные вопросы, является статья «How do I ask a good question?»

Резюме  119

на форуме Stack Overflow (https://stackoverflow.com/help/how-to-ask). Формулируйте
свои вопросы, уважая время других людей, тогда более опытные пользователи
будут охотнее на них отвечать. Ваш вопрос должен быть кратким и по существу,
включать сообщения об ошибках или другие выходные данные и объяснять, что
вы уже пробовали сделать самостоятельно. Потратив время, чтобы сформулировать качественный вопрос, вы увеличите шансы на полезный ответ не только
для себя, но и для других людей, которые столкнулись со схожей проблемой.

Резюме
Теперь вы вышли за рамки инструментария размером с чайную ложку из
главы 1 и готовы решать сложные задачи. Следующие главы наполнены практическими примерами использования команд, которые вы узнали, в самых
разных ситуациях.

ГЛАВА 6

Родители, потомки и окружение

Назначение оболочки — выполнение команд — настолько фундаментально, что
можно подумать, что оболочка встроена в Linux каким-то особым образом. Но
это не так. Оболочка — это обычная программа, такая как ls или cat. Она запрограммирована на повторение следующих шагов снова и снова, снова и снова…
1. Вывести приглашение командной строки.
2. Прочитать команду из стандартного ввода.
3. Интерпретировать и запустить команду.
Linux прекрасно скрывает тот факт, что оболочка — это обычная программа. Когда
вы входите в систему, Linux автоматически запускает для вас экземпляр оболочки,
известный как командная оболочка входа в систему (login shell). Она запускается
так плавно, что кажется , будто это и есть сам Linux, хотя на самом деле это просто
программа, запущенная от вашего имени для взаимодействия с Linux.

Где находится ваша оболочка входа?
Если вы входите в систему без графического интерфейса, скажем, с помощью клиентской программы SSH, оболочка входа в систему является
начальной оболочкой, с которой вы взаимодействуете. Она печатает первое
приглашение и ожидает вашей команды.
Если же вы используете версию с графическим интерфейсом, ваша оболочка входа в систему выполняется незаметно для вас. Она запускает среду
рабочего стола, такую как GNOME, Unity, Cinnamon или KDE Plasma.
Затем вы можете открыть окна терминала для запуска дополнительных
интерактивных экземпляров оболочки.

Чем больше вы понимаете в устройстве оболочки, тем эффективнее сможете
работать с Linux и тем меньше «магии» останется. В этой главе более детально,
чем в главе 2, рассмотрены следующие загадки оболочки:

Оболочки — это исполняемые файлы  

121

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

Оболочки — это исполняемые файлы
Оболочкой по умолчанию в большинстве систем Linux является bash1, и это
обычная программа — исполняемый файл, расположенный в системном каталоге
/bin вместе с cat, ls, grep и другими знакомыми командами:
$ cd /bin
$ ls -l bash
-rwxr-xr-x 1
-rwxr-xr-x 1
-rwxr-xr-x 1
-rwxr-xr-x 1

cat ls grep
root root 1113504 Jun 6 2019 bash
root root 35064 Jan 18 2018 cat
root root 219456 Sep 18 2019 grep
root root 133792 Jan 18 2018 ls

Скорее всего, bash — не единственная возможная оболочка в вашей системе.
Допустимые оболочки обычно перечислены в файле /etc/shells:
$ cat /etc/shells
/bin/sh
/bin/bash
/bin/csh
/bin/zsh

Чтобы узнать, какую оболочку вы используете, примените команду echo к переменной оболочки SHELL:
$ echo $SHELL
/bin/bash

Теоретически система Linux может рассматривать любую программу как допустимую оболочку входа, если учетная запись пользователя настроена на вызов
ее при входе в систему и она указана в /etc/shells (если это требуется в вашей
системе). Обладая привилегиями суперпользователя, вы даже можете написать
и установить свою собственную оболочку, такую, например, как в листинге 6.1.
1

Если вы используете другую оболочку, обратите внимание на Приложение Б.

122  Глава 6. Родители, потомки и окружение

Она читает любую команду и отвечает: «Извините, боюсь, я не могу этого
сделать». Эта пользовательская оболочка намеренно сделана глупой, но она
демонстрирует, что другие программы могут быть такой же легитимной оболочкой, как /bin/bash.
Листинг 6.1. halshell: оболочка, которая отказывается выполнять ваши команды
#!/bin/bash
# Вывод приглашения командной строки
echo -n '$ '
# Чтение ввода пользователя в цикле. Выход, когда пользователь нажимает Ctrl-D
while read line; do
# Игнорировать входную строку $line и вывести сообщение
echo "Извините, боюсь, я не могу этого сделать"
# Вывод следующего приглашения командной строки
echo -n '$ '
done

Поскольку bash — это просто программа, вы можете запустить ее вручную, как
и любую другую команду:
$ bash

Если вы это сделаете, вы просто увидите еще одно приглашение, как будто ваша
команда не имела никакого эффекта:
$

Но на самом деле вы запустили новый экземпляр bash. Этот новый экземпляр
печатает приглашение и ожидает вашей команды. Чтобы как-то выделить новый
экземпляр, измените его приглашение командной строки (скажем, на %%) с помощью переменной оболочки PS1 и выполните несколько команд:
$ PS1="%% "
%% ls
Приглашение изменилось
animals.txt
%% echo "This is a new shell"
This is a new shell

Теперь запустите команду exit, чтобы завершить работу нового экземпляра
bash. Вы вернетесь к исходной оболочке, в которой используется приглашение
со знаком доллара:
%% exit
$

Необходимо отметить, что изменение с %% обратно на $ не было просто изменением приглашения командной строки. Это была полная смена оболочки. Работа

Родительский и дочерний процессы  

123

нового экземпляра bash завершена, поэтому исходная оболочка запрашивает
следующую команду.
Запуск bash вручную нужен не только для развлечения. Вы будете использовать
вызываемые вручную экземпляры оболочки в главе 7.

Родительский и дочерний процессы
Когда один экземпляр оболочки вызывает другой, как только что было показано,
исходная оболочка называется родительской, а новый экземпляр — дочерней.
То же самое верно для любой программы, которая вызывает другую программу
Linux. Вызывающая программа является родительской, а вызываемая — дочерней.
Работающая программа Linux называется процессом, поэтому вы также встретите
термины родительский процесс и дочерний процесс, или потомок. Процесс может
иметь любое количество потомков, но у каждого потомка есть только один родитель.
У каждого процесса есть свое окружение. Окружение, которое вы, возможно,
помните из раздела «Окружение и файлы инициализации, краткая версия» на
с. 50, включает в себя текущий каталог, путь поиска, приглашение оболочки
и другую важную информацию, хранящуюся в переменных оболочки. Когда
создается дочерний элемент, его окружение в значительной степени является
копией окружения его родителя (подробности см. в разделе «Переменные
окружения» на с. 125).
Каждый раз, когда вы запускаете простую команду, вы создаете дочерний процесс. Это настолько важный момент для понимания Linux, что повторим еще
раз: даже когда вы запускаете простую команду, такую как ls, она выполняется
внутри нового дочернего процесса со своим собственным (скопированным)
окружением. Это означает, что любые изменения, которые вы вносите в дочерний процесс, например изменение переменной приглашения PS1 в дочерней
оболочке, влияют только на дочерний процесс и теряются при выходе из него.
Точно так же любые изменения в родительском элементе не повлияют на его
дочерние элементы, которые уже запущены. Однако изменения в родительском
объекте могут повлиять на его будущие дочерние элементы, поскольку окружение
каждого дочернего объекта копируется при запуске из родительского.
Почему важно, чтобы команды выполнялись в дочерних процессах? Прежде
всего, любая программа, которую вы запускаете, может выполнять команду cd
по всей файловой системе, но, когда она завершается, ваша текущая оболочка
(родительская) не меняет свой текущий каталог. Проведем эксперимент, чтобы
доказать это. Создайте в своем домашнем каталоге небольшой сценарий с именем
cdtest, содержащий команду cd:

124  Глава 6. Родители, потомки и окружение

#!/bin/bash
cd /etc
echo "Here is my current directory:"
pwd

Сделайте его исполняемым:
$ chmod +x cdtest

Выведите имя текущего каталога и запустите скрипт:
$ pwd
/home/smith
$ ./cdtest
Here is my current directory:
/etc

Теперь проверьте ваш текущий каталог:
$ pwd
/home/smith

Ваш текущий каталог не изменился, хотя скрипт cdtest переместился в каталог
/etc. Это потому, что cdtest запускается внутри дочернего процесса со своим
собственным окружением. Изменения в дочернем окружении не могут повлиять на родительское, поэтому текущий каталог родителя не изменился. То же
самое происходит, когда вы запускаете исполняемую программу, такую как cat
или grep, — она запускается в дочернем процессе, который завершается после
окончания работы программы, забирая с собой любые изменения окружения.

Почему команда cd должна быть встроенной в оболочку
Если программы Linux не могут изменить текущий каталог вашей оболочки, то как команда cd может изменить его? Оказывается, cd — это не
программа, а встроенная функция оболочки (shell builtin). Если бы cd была
внешней по отношению к оболочке программой, изменения каталога были
бы невозможны, так как они выполнялись бы в дочернем процессе и не
могли бы повлиять на родительский процесс.

Конвейеры запускают несколько дочерних процессов: по одному для каждой
команды в конвейере. Например, эта команда из раздела «Команда 6: uniq»
на с. 30 запускает шесть потомков:
$ cut -f1 grades | sort | uniq -c | sort -nr | head -n1 | cut -c9

Переменные окружения  

125

Переменные окружения
Каждый экземпляр оболочки имеет свой набор переменных, как вы узнали из
раздела «Вычисление переменных» на с. 40. Некоторые переменные существуют
только в одной конкретной оболочке. Они называются локальными переменными.
Другие переменные автоматически копируются из оболочки во все ее дочерние
элементы. Это переменные окружения, и все вместе они формируют окружение
оболочки.
Некоторые примеры переменных окружения и их использования.
HOME — путь к вашему домашнему каталогу. Его значение автоматически уста-

навливается оболочкой при входе в систему. Текстовые редакторы, такие как
vim и emacs, читают переменную HOME, чтобы найти свои файлы конфигурации
($HOME/.vim и $HOME/.emacs соответственно).
PWD — текущий каталог вашей оболочки. Его значение автоматически устанавли-

вается и поддерживается оболочкой каждый раз, когда вы переходите в другой
каталог с помощью команды cd. Команда pwd считывает переменную PWD, чтобы
вывести имя текущего каталога вашей оболочки.
EDITOR — имя или путь предпочитаемого вами текстового редактора. Его значение

обычно задается в файле конфигурации оболочки. Другие программы читают
эту переменную, чтобы запустить соответствующий редактор от вашего имени.
Просмотрите переменные окружения вашей оболочки с помощью команды
printenv. Вывод представляет собой несортированный набор строк — по одной
переменной в строке, и может быть довольно длинным, поэтому используйте
конвейер из sort и less для более удобного просмотра1:
$ printenv | sort -i | less

DISPLAY=:0
EDITOR=emacs
HOME=/home/smith
LANG=en_US.UTF-8
PWD=/home/smith/Music
SHELL=/bin/bash
TERM=xterm-256color
USER=smith

1

Я сократил вывод, оставив только самые общие переменные оболочки. Ваш вывод, вероятно,
намного длиннее и полон неясных имен переменных.

126  Глава 6. Родители, потомки и окружение

Локальные переменные не отображаются в выводе printenv. Проверьте их значения, поставив перед именем переменной знак доллара, с помощью команды echo:
$ title="Efficient Linux"
$ echo $title
Efficient Linux
$ printenv title

(пустой вывод)

Создание переменных окружения
Чтобы превратить локальную переменную в переменную окружения, используйте команду export:
$ MY_VARIABLE=10
$ export MY_VARIABLE
$ export ANOTHER_VARIABLE=20

Присвоим значение локальной переменной
Экспортируем, чтобы она стала переменной окружения
Все вместе в одной команде

export означает, что переменная и ее значение будут скопированы из текущей
оболочки во всех ее будущих потомков. Локальные переменные не копируются
в будущие дочерние элементы:
$ export E="I am an environment variable"
Установить переменную оболочки
$ L="I am just a local variable"
Установить локальную переменную
$ echo $E
I am an environment variable
$ echo $L
I am just a local variable
$ bash Запустить дочернюю оболочку
$ echo $E Переменная оболочки была скопирована
I am an environment variable
$ echo $L Локальная переменная не была скопирована
Вывод пустой строки
$ exit Выход из дочернего процесса

Помните, что дочерние переменные — это копии. Любые изменения в копиях не
влияют на родительскую оболочку:
$ export E="I am the original value"
Установить переменную оболочки
$ bash Запустить дочернюю оболочку
$ echo $E
I am the original value
Родительское значение было скопировано
$ E="I was modified in a child"
Изменить дочернюю копию
$ echo $E
I was modified in a child
$ exit Выход из дочерней оболочки
$ echo $E
I am the original value
Родительское значение переменной осталось
без изменений

Переменные окружения  

127

Запустите новую оболочку и измените что-либо в ее окружении, но все изменения
исчезнут, когда вы выйдете из оболочки. Это означает, что вы можете безопасно экспериментировать с функциями оболочки — просто запустите оболочку
вручную, создав дочернюю, и завершите ее, когда закончите.

Предупреждение о мифе: «глобальные» переменные
Иногда Linux слишком хорошо скрывает свою внутреннюю работу. Отличный
пример — поведение переменных окружения. Каким-то образом, как по волшебству, такие переменные, как HOME и PATH, имеют постоянное значение во всех
экземплярах вашей оболочки. В каком-то смысле они кажутся «глобальными
переменными» (это утверждение встречается в других книгах по Linux, не
выходивших в издательстве O'Reilly). Но переменная окружения не является
глобальной. Каждый экземпляр оболочки имеет свою собственную копию. Изменение переменной окружения в одной оболочке не может изменить ее значение ни в одной другой запущенной оболочке. Модификации влияют только на
будущих потомков этой оболочки (еще не вызванных).
Но каким образом такая переменная, как HOME или PATH, сохраняет свое значение
во всех экземплярах вашей оболочки? Для этого есть две причины, которые
проиллюстрированы на рис. 6.1. Если коротко:
Потомки копируют своих родителей.
Значения таких переменных, как HOME, обычно устанавливаются и экспортируются вашей оболочкой входа в систему. Все будущие оболочки (пока
вы не выйдете из системы) являются потомками оболочки входа в систему,
поэтому они получают копию переменной и ее значение. Такого рода определяемые системой переменные окружения настолько редко изменяются
в реальной работе, что кажутся глобальными, но на самом деле это обычные
переменные, подчиняющиеся общим правилам (вы даже можете изменить
их значения в работающей оболочке, но при этом возможно нарушение
ожидаемого поведения этой командной оболочки и других программ).
Разные экземпляры оболочки читают одни и те же файлы конфигурации.
Значения локальных переменных, которые не копируются в дочерние
элементы, могут быть установлены в файле конфигурации Linux, например $HOME/.bashrc (подробнее см. в разделе «Настройка окружения»
на с. 129). Каждый экземпляр оболочки при вызове считывает и выполняет соответствующие файлы конфигурации. В результате эти локальные
переменные кажутся копируемыми из оболочки в оболочку. То же самое
относится и к другим неэкспортируемым сущностям оболочки, например псевдонимам.

128  Глава 6. Родители, потомки и окружение

Такое поведение заставляет некоторых пользователей полагать, что команда
export создает глобальную переменную. Это не так. Команда export WHATEVER
просто объявляет, что переменная WHATEVER будет скопирована из текущей оболочки во все будущие дочерние элементы.

Рис. 6.1. Экземпляры оболочки могут использовать одни и те же значения
переменных благодаря экспорту или чтению общих файлов конфигурации

Дочерние оболочки vs подоболочки
Потомок является частичной копией своего родителя. Например, он включает
копии переменных окружения своего родителя, но не локальные (неэкспортированные) переменные или псевдонимы родителя:
$ alias
Список псевдонимов
alias gd='pushd'
alias l='ls -CF'
alias pd='popd'
$ bash --norc Запустить дочернюю оболочку и игнорировать файл .bashrc
$ alias
Список псевдонимов — ни один не известен
$ echo $HOME Переменные окружения известны
/home/smith
$ exit
Выход из дочерней оболочки

Если вы когда-нибудь задумывались, почему ваши псевдонимы недоступны
в сценариях оболочки, теперь вы знаете ответ. Сценарии запускаются в дочернем
элементе, который не получает копии псевдонимов своего родителя.

Настройка окружения  

129

Подоболочка, напротив, является полной копией своего родителя1. Она включает
в себя все родительские переменные, псевдонимы, функции и многое другое.
Чтобы запустить команду в подоболочке, заключите ее в круглые скобки:
$ (ls -l) Запускает ls -l в подоболочке
-rw-r--r-- 1 smith smith 325 Oct 13 22:19 animals.txt
$ (alias) Просмотр псевдонимов в подоболочке
alias gd=pushd
alias l=ls -CF
alias pd=popd

$ (l) Запуск псевдонима от родителя
animals.txt

Чтобы проверить, является ли экземпляр оболочки подоболочкой, выведите
переменную BASH_SUBSHELL. В подоболочках значение будет отлично от нуля:
$
0
$
$
0
$
$
1

echo $BASH_SUBSHELL Проверяем текущий экземпляр оболочки
Это не подоболочка
bash Запускаем дочернюю оболочку
echo $BASH_SUBSHELL Проверяем дочернюю оболочку
Это не подоболочка
exit Выходим из дочерней оболочки
(echo $BASH_SUBSHELL) Явно запускаем подоболочку
Это подоболочка

Некоторые практические применения подоболочек мы рассмотрим в разделе
«Способ 10: Явные подоболочки» на с. 159. А пока просто имейте в виду, что вы
можете создавать их и они копируют псевдонимы родителя.

Настройка окружения
Когда команда bash запускается, она настраивает себя, читая и выполняя последовательность файлов конфигурации. Эти файлы определяют переменные,
псевдонимы, функции, другие свойства оболочки и могут запускать любую
команду Linux (они похожи на сценарии настройки оболочки). В каталоге /etc
файлы конфигурации определяются системным администратором и применяются ко всем пользователям системы. Другие файлы конфигурации принадлежат
отдельным пользователям и изменяются ими. Они расположены в домашнем
каталоге пользователя. В табл. 6.1 перечислены стандартные файлы конфигурации bash. Они делятся на нескольких типов:
1

Копия полная, за исключением ловушек, которые «сбрасываются до значений, унаследованных оболочкой от своего родителя при вызове» (man bash). В этой книге мы не будем
обсуждать ловушки.

130  Глава 6. Родители, потомки и окружение

Файлы запуска
Файлы конфигурации, которые выполняются автоматически при входе
в систему, то есть они применяются только к вашей оболочке входа в систему. К примеру, команда в таком файле может установить и экспортировать переменную оболочки. Однако определение псевдонима в этом
файле малополезно, поскольку псевдонимы не копируются в дочерние
элементы.
Файлы инициализации
Файлы конфигурации, которые выполняются для каждого экземпляра
оболочки, за исключением оболочки входа в систему, например когда
вы вручную запускаете интерактивную оболочку или сценарий неинтерактивной оболочки. Команды файла инициализации могут установить
переменную или определить псевдоним.
Файлы очистки при выходе
Файлы конфигурации, которые выполняются непосредственно перед
выходом из оболочки входа в систему. Например, в таком файле может
быть команда clear, очищающая экран при выходе из системы.

Таблица 6.1. Стандартные файлы конфигурации, используемые в bash
Тип файла

Файлы
запуска

Чем запускается

Общесистемное
местоположение

Оболочка входа в систе- /etc/profile
му (при вызове)

Файлы
Интерактивная обоинициализации лочка (без авторизации).
Сценарии оболочки (при
вызове)

/etc/bash.bashrc

Расположение личных
файлов (в порядке вызова)
$HOME/.bash_profile,
$HOME/.bash_login, and
$HOME/.profile
$HOME/.bashrc

Задайте для переменной
BASH_ENV абсолютный
путь к файлу инициализации (пример: BASH_

Задайте для переменной
BASH_ENV абсолютный
путь к файлу инициализации
(пример: BASH_ENV=/usr/
ENV=/usr/local/etc/ local/etc/bashrc)
bashrc)

Файлы очистки Оболочка входа в систе- /etc/bash.bash_logout
му (при выходе)

$HOME/.bash_logout

Обратите внимание, что у вас есть три варианта файлов запуска в вашем
домашнем каталоге: .bash_profile, .bash_login и .profile. Большинство пользователей могут выбрать только один из них. Ваш дистрибутив Linux, вероятно,

Настройка окружения  

131

уже предоставляет один из этих файлов предварительно заполненным полезными командами. Но, если вы используете не bash, а, например, Bourne (/bin/
sh) или Korn (/bin/ksh), они читают .profile и могут дать сбой, если этот файл
содержит команды, специфичные для bash. Поэтому поместите специфичные
для bash команды в .bash_profile или .bash_login (выберите один из них и используйте только его).
Иногда пользователей сбивает с толку возможность использования разных
файлов запуска и инициализации. Почему вы хотите, чтобы ваша оболочка
входа в систему вела себя иначе, чем другие оболочки, например те, которые
вы открываете в нескольких окнах? Как правило, вам не нужно, чтобы они
вели себя по-разному. Ваш файл запуска может делать немного больше, чем
файл инициализации $HOME/.bashrc, тогда все интерактивные оболочки
(требующие или не требующие входа в систему) будут иметь одинаковую
конфигурацию.
Когда вы входите в графическое окружение рабочего стола (GNOME, Unity,
KDE Plasma и т. д.), оболочка входа может быть скрыта. В этом случае оболочка
входа в систему не имеет значения, так как вы взаимодействуете только с ее дочерними элементами. Поэтому вы можете поместить большую часть или даже
всю конфигурацию в файл $HOME/.bashrc1. С другой стороны, если вы входите
в систему из неграфической терминальной программы, такой, например, как
SSH-клиент, то напрямую взаимодействуете со своей оболочкой входа, поэтому
ее конфигурация имеет большое значение.
В каждом из перечисленных случаев, как правило, имеет смысл, чтобы ваш
личный файл запуска имел в качестве источника файл инициализации:
# Поместите в $HOME/.bash_profile или другой персональный файл запуска
if [ -f "$HOME/.bashrc" ]
then
source "$HOME/.bashrc"
fi

В любом случае старайтесь не помещать одинаковые команды в два разных файла
конфигурации. Это приводит к путанице, такую систему трудно поддерживать,
потому что любое изменение в одном файле надо не забыть продублировать
в другом (и вы обязательно забудете, поверьте мне). Вместо этого используйте
один файл в качестве источника для другого, как показано выше.

1

Чтобы еще немного запутать ситуацию, некоторые окружения рабочего стола имеют свои
собственные файлы конфигурации оболочки. Например, в GNOME есть $HOME/.gnomerc,
а в базовой системе X Window — $HOME/.xinitrc.

132  Глава 6. Родители, потомки и окружение

Повторное считывание файла конфигурации
Когда вы изменяете файлы запуска или инициализации, то можете заставить
работающую оболочку повторно считать его, как описано в разделе «Окружения
и файлы инициализации, краткая версия» на с. 50:
$ source ~/.bash_profile
$ . ~/.bash_profile

Используется встроенная команда source
Используется точка

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

Путешествие с вашим окружением
Если вы используете несколько компьютеров с Linux в разных местах, в какойто момент может понадобиться установить отлаженные файлы конфигурации
более чем на одну машину. Не копируйте отдельные файлы из одной системы
в другую — такой подход в конечном итоге приведет к путанице. Вместо этого
храните и обновляйте файлы в бесплатном сервисе GitHub (https://github.com/)
или аналогичном, поддерживающем контроль версий. В этом случае вы сможете быстро загружать, устанавливать и обновлять файлы конфигурации на
любом компьютере с Linux. Если вы допустили ошибку при редактировании
файла конфигурации, то можете вернуться к предыдущей версии, выполнив
одну или две команды. Контроль версий выходит за рамки этой книги. Чтобы узнать больше, см. раздел «Применяйте контроль версий к повседневным
файлам» на с. 230.
Если вам не нравятся системы контроля версий вроде Git или Subversion, храните файлы конфигурации в облачном хранилище, таком как Dropbox, Google
Drive или One-Drive. Обновление ваших файлов конфигурации будет менее
удобным, но по крайней мере файлы будут легко доступны для копирования
в другие системы Linux.

Резюме  133

Резюме
Многие пользователи Linux понятия не имеют о родительских и дочерних
процессах, окружениях и назначении многих файлов конфигурации оболочки.
Я надеюсь, что после прочтения главы у вас сложится четкое представление
обо всех этих вещах. Оно понадобится в главе 7 как основа инструментария для
гибкого выполнения команд.

ГЛАВА 7

Еще 11 способов запуска команды

Теперь, когда вы знаете множество команд и хорошо разбираетесь в оболочке,
пришло время научиться… запускать команды. «Разве мы не запускали команды с самого начала книги?» — спросите вы. Ну да, но только двумя способами.
Первый — это обычное выполнение простой команды:
$ grep Nutshell animals.txt

Второй — это конвейер простых команд, описанный в главе 1:
$ cut -f1 grades | sort | uniq -c | sort -nr

В этой главе мы рассмотрим еще 11 способов запуска команды и узнаем, почему
их следует изучить. У каждого способа есть свои плюсы и минусы, и чем больше их вы знаете, тем гибче и эффективнее сможете взаимодействовать с Linux.
Пока что ознакомимся с основами каждого способа. В следующих двух главах
вы увидите более сложные примеры.

Способы, использующие списки
Список — это последовательность команд, расположенных в одной командной
строке. Вы уже видели один тип списка — конвейер, но оболочка поддерживает
и другие, которые ведут себя не так, как конвейеры:
Условные списки
Каждая последующая команда зависит от результата выполнения предыдущей.
Безусловные списки
Команды выполняются одна за другой.

Способы, использующие списки  

135

Способ #1. Условные списки
Предположим, вы хотите создать файл new.txt в каталоге dir. Типичная последовательность команд может быть следующей:
$ cd dir Перейти в каталог
$ touch new.txt
Создать файл

Обратите внимание, что запуск второй команды зависит от успешного выполнения первой. Если каталог dir не существует, нет смысла запускать команду
touch. Оболочка позволяет сделать эту зависимость явной, поместив оператор
&& (произносится как и) между двумя командами в одной строке:
$ cd dir && touch new.txt

Теперь вторая команда (touch) выполнится только в том случае, если первая
команда (cd) выполнена успешно. Предыдущий пример представляет собой
условный список из двух команд (чтобы узнать, что означает успешное выполнение команды, см. раздел «Коды возврата, указывающие на успех или неудачу»
на с. 136).
Скорее всего, вы каждый день запускаете команды, которые зависят от выполнения предыдущих. Например, делали ли вы когда-нибудь резервную копию
файла, а после изменения оригинала ее удаляли?
$ cp myfile.txt myfile.safe Создать резервную копию
$ nano myfile.txt Изменить оригинальный файл
$ rm myfile.safe
Удалить резервную копию

Каждая из этих команд имеет смысл только в том случае, если предыдущая
выполнена успешно. Таким образом, эта последовательность команд является
кандидатом для составления условного списка:
$ cp myfile.txt myfile.safe && nano myfile.txt && rm myfile.safe

Если вы используете систему контроля версий Git, то, вероятно, знакомы со
следующей последовательностью команд после изменения некоторых файлов:
запустить git add, чтобы подготовить файлы для снимка состояния (commit),
затем git commit и, наконец, git push, чтобы поделиться изменениями. Если
какая-либо из этих команд завершится ошибкой, остальные вы не запустите
(пока не устраните причину ошибки). Поэтому эти три команды хорошо работают в формате условного списка:
$ git add . && git commit -m"fixed a bug" && git push

Так же, как оператор && запускает вторую команду только в случае успеха первой,
оператор || (произносится как или) запускает вторую команду только в случае

136  Глава 7. Еще 11 способов запуска команды

сбоя первой. Например, следующая команда пытается войти в каталог и, если
это не удается, создает его1:
$ cd dir || mkdir dir

Вы часто будете видеть оператор || в сценариях. В частности, он используется
для выхода в случае возникновения ошибки:
# Если не удается войти в каталог, выйдите с кодом ошибки 1
cd dir || exit 1

Объединяйте операторы && и ||, чтобы настраивать более сложные действия,
которые используют успешные или неудачные попытки выполнить команду.
Следующая команда пытается войти в каталог dir; если это не удается, пробует
создать каталог и войти в него; а если и это не удается, выводит сообщение об
ошибке:
$ cd dir || mkdir dir && cd dir || echo "I failed"

Команды в условном списке не обязательно должны быть простыми, это могут
быть конвейеры и другие комбинированные команды.
КОДЫ ВОЗВРАТА, УКАЗЫВАЮЩИЕ НА УСПЕХ ИЛИ НЕУДАЧУ
Что означает успешное или неудачное выполнение команды Linux?
Каждая команда Linux при завершении выдает результат, называемый кодом возврата (exit code). По соглашению, нулевой код
возврата означает успех, а любое ненулевое значение — сбой2. Просмотрите код возврата последней выполненной команды оболочки,
напечатав специальную переменную оболочки ?:
$ ls myfile.txt
myfile.txt
$ echo $?
Вывести значение переменной ?
0 ls выполнена успешно
$ cp nonexistent.txt somewhere.txt
cp: cannot stat 'nonexistent.txt': No such file or directory
$ echo $?
1 cp выполнена неудачно

1

2

Команда mkdir -p dir, которая создает путь к каталогу, только если он еще не существует,
была бы более элегантным решением для этого случая.
Это противоположно многим языкам программирования, где ноль означает неудачу.

Способы, использующие подстановку  

137

Способ #2. Безусловные списки
Команды в списке не обязательно должны зависеть друг от друга. Если вы разделяете команды точкой с запятой, они просто выполняются по порядку. Успех
или неудача одной команды не влияет на более поздние в списке.
Безусловные списки для запуска команд удобны, если надо уйти с работы на
весь день. Вот пример команды, которая спит (ничего не делает) в течение двух
часов (7200 секунд), а затем создает резервную копию всех важных файлов:
$ sleep 7200; cp -a ~/important-files /mnt/backup_drive

А вот аналогичная команда, которая работает как простейшая система напоминаний, спит пять минут, а затем отправляет вам электронное письмо3:
$ sleep 300; echo "remember to walk the dog" | mail -s reminder $USER

Безусловные списки — удобная функция, в большинстве случаев они дают те
же результаты, что и ввод команд по отдельности и нажатие Enter после каждой.
Единственное существенное различие касается кодов возврата. В безусловном
списке коды возврата отдельных команд отбрасываются, кроме последней.
Только код возврата последней команды в списке присваивается переменной
оболочки ?:
$ mv file1 file2; mv file2 file3; mv file3 file4
$ echo $?
0 Код возврата команды «mv file3 file4»

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

3

В качестве альтернативы вы можете использовать cron для задания резервного копирования
и команду at для напоминаний, но в Linux главное гибкость — наличие нескольких решений
для достижения одного и того же результата.

138  Глава 7. Еще 11 способов запуска команды

Способ #3. Подстановка команд
Предположим, у вас есть несколько тысяч текстовых файлов c песнями. Каждый
файл содержит название песни, имя исполнителя, название альбома и текст песни:
Title: Carry On Wayward Son
Artist: Kansas
Album: Leftoverture
Carry on my wayward son
There'll be peace when you are done


Вы хотите распределить файлы в подкаталоги по исполнителям. Выполняя эту
задачу вручную, вы можете найти все файлы песен исполнителя Kansas с помощью команды grep:
$ grep -l "Artist: Kansas" *.txt
carry_on_wayward_son.txt
dust_in_the_wind.txt
belexes.txt

а затем переместить каждый файл в каталог kansas:
$
$
$
$

mkdir kansas
mv carry_on_wayward_son.txt kansas
mv dust_in_the_wind.txt kansas
mv belexes.txt kansas

Утомительно, правда? Было бы неплохо, если бы вы могли сказать оболочке:
«Переместите все файлы, содержащие строку Artist: Kansas, в каталог kansas».
В терминах Linux требуется взять список имен из предыдущей команды grep -l
и передать его команде mv. Что ж, вы можете сделать это с помощью функции
оболочки, называемой подстановкой команд:
$ mv $(grep -l "Artist: Kansas" *.txt) kansas

Следующий синтаксис:
$(команда)

выполняет команду в круглых скобках и заменяет команду ее выводом. Таким
образом, в предыдущей командной строке команда grep -l заменяется списком
имен файлов, которые она выводит, как если бы вы вводили имена файлов
следующим образом:
$ mv carry_on_wayward_son.txt dust_in_the_wind.txt belexes.txt kansas

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

Способы, использующие подстановку  

139

Специальные символы и подстановка команд
Предыдущий пример с grep -l прекрасно работает для большинства имен
файлов, если они не содержат пробелы или другие специальные символы.
Оболочка интерпретирует эти символы перед передачей вывода команде
mv, что может привести к неожиданным результатам. Например, если
grep -l выведет dust in the wind.txt, оболочка будет рассматривать пробелы
как разделители, а mv попытается переместить четыре несуществующих
файла с именами dust, in, the и wind.txt.

Рассмотрим еще один пример. Предположим, у вас есть банковские выписки
за несколько лет в формате PDF. Файлы имеют имена, включающие год, месяц
и день выписки, например eStmt_2021-08-26.pdf для даты 26 августа 2021 года1.
Вы хотите просмотреть последнюю выписку в текущем каталоге. Это можно
сделать вручную: просмотреть каталог, найти файл с самой последней датой
(который будет последним файлом в списке) и открыть его с помощью программы просмотра PDF для Linux, такой как okular.
Но зачем делать всю эту ручную работу? Позвольте подстановке команд сэкономить ваше время. Создадим команду, которая выводит имя последнего файла
PDF в каталоге:
$ ls eStmt*pdf | tail -n1

и отправим его программе okular с помощью подстановки команд:
$ okular $(ls eStmt*pdf | tail -n1)

Команда ls выводит список всех подходящих файлов, а tail — только последний из них, например eStmt_2021-08-26.pdf. Подстановка команд помещает это
единственное имя файла прямо в командную строку, как если бы вы набрали
okular eStmt_2021-08-26.pdf.
Исходным синтаксисом для подстановки команд были обратные кавычки.
Следующие две команды эквивалентны:
$ echo Today is $(date +%A).
Today is Saturday.
$ echo Today is `date +%A`.
Today is Saturday.

1

Выписки Bank of America до сих пор имеют такой формат.

140  Глава 7. Еще 11 способов запуска команды

Обратные кавычки поддерживаются большинством оболочек. Однако синтаксис $() проще для восприятия при использовании вложенных команд:
$ echo $(date +%A) | tr a-z A-Z
SATURDAY
echo Today is $( echo $(date +%A) | tr a-z A-Z )!
Today is SATURDAY!

Одиночная команда
Вложенная команда

В сценариях подстановка команд обычно используется для сохранения вывода
команды в переменной:
переменная=$(команда)
Например, чтобы получить имена файлов, содержащих песни исполнителя
Kansas, и сохранить их в переменной, используйте подстановку команд следующим образом:
$ kansasFiles=$(grep -l "Artist: Kansas" *.txt)

Вывод может состоять из нескольких строк, поэтому, чтобы сохранить все символы новой строки, убедитесь, что значение заключено в кавычки везде, где вы
его используете:
$ echo "$kansasFiles"

Способ #4. Подстановка процесса
Подстановка команд, которую вы только что видели, заменяет команду ее
выводом в виде строки. Подстановка процесса также заменяет команду ее
выводом, но обрабатывает вывод так, как если бы он был сохранен в файле.
Поначалу это различие может показаться непонятным, поэтому разберемся
в нем шаг за шагом.
Предположим, вы находитесь в каталоге файлов изображений JPEG с именами
от 1.jpg до 1000.jpg, но некоторые файлы загадочным образом отсутствуют, и вы
хотите выяснить, какие именно. Создайте такой каталог с помощью следующих
команд:
$ mkdir /tmp/jpegs && cd /tmp/jpegs
$ touch {1..1000}.jpg
$ rm 4.jpg 981.jpg

Плохой способ найти отсутствующие файлы — составить список файлов из
каталога, отсортированных по номерам, и искать пропущенные файлы глазами:

Способы, использующие подстановку  

141

$ ls -1 | sort -n | less
1.jpg
2.jpg
3.jpg
5.jpg 4.jpg пропущен


Более надежным автоматизированным решением станет сравнение существующих имен файлов с полным списком имен от 1.jpg до 1000.jpg с помощью команды diff. Один из способов добиться этого — использовать временные файлы.
Сохраните отсортированные существующие имена файлов в одном временном
файле original-list:
$ ls *.jpg | sort -n > /tmp/original-list

Затем выведите полный список имен файлов от 1.jpg до 1000.jpg в другой временный файл, full-list. Это можно сделать, сгенерировав целые числа от 1 до
1000 с помощью команды seq и добавив .jpg к каждой строке с помощью sed:
$ seq 1 1000 | sed 's/$/.jpg/' > /tmp/full-list

Сравните два временных файла с помощью команды diff, чтобы обнаружить,
что 4.jpg и 981.jpg отсутствуют, а затем удалите временные файлы:
$ diff /tmp/original-list /tmp/full-list
3a4
> 4.jpg
979a981
> 981.jpg
$ rm /tmp/original-list /tmp/full-list

Очистить после завершения

Потребовалось довольно много шагов. Разве не было бы здорово сравнить два
списка имен напрямую и не возиться с временными файлами? Проблема в том,
что команда diff не может сравнить два списка из стандартного ввода, в качестве
аргументов ей требуются файлы1. Подстановка процесса решает эту проблему.
Она заставляет оба списка выглядеть для diff как файлы (раздел «Как работает
подстановка процессов» на с. 143 содержит технические подробности). Синтаксис
outfile
$ ssh myhost.example.com "ls > outfile"

Создает outfile на локальном хосте
Создает outfile на удаленном хосте

Помимо этого, вы можете передавать команды в ssh для запуска на удаленном
хосте так же, как в bash для локального запуска:
$ echo "ls > outfile" | ssh myhost.example.com

При передаче команд в ssh удаленный хост может вывести диагностические
или другие сообщения. Как правило, они не влияют на удаленную команду, и вы
можете избавиться от них:
Если вы видите сообщения о псевдотерминалах (pseudo-ttys), например
Pseudoterminal will not be allocated because stdin is not a terminal (псевдотерминал не будет выделен, поскольку стандартный ввод не является
терминалом), запустите ssh с параметром -T, чтобы удаленный SSHсервер не выделял терминал:
$ echo "ls > outfile" | ssh -T myhost.example.com

Если вы видите приветственные сообщения, которые обычно появляются при входе в систему (Welcome to Linux!) или другие нежелательные
сообщения, попробуйте указать команде ssh явно запустить bash на удаленном хосте, и сообщения должны исчезнуть:
$ echo "ls > outfile" | ssh myhost.example.com bash

Способ #8. Запуск списка команд с помощью xargs
Многие пользователи Linux никогда не слышали о команде xargs, хотя это
мощный инструмент для создания и запуска нескольких похожих команд.
Знакомство с xargs стало еще одним переломным моментом в моем освоении
Linux, и я надеюсь, что оно станет таковым и для вас.

Команда как строка  

149

xargs обрабатывает входные данные из двух источников:

стандартного потока ввода: списки строк, разделенных пробелом. Примером могут служить пути к файлам, создаваемые ls или find, но подойдут любые строки. Назовем их входными строками;
командной строки: неполные команды, в которых отсутствуют некоторые аргументы (назовем их шаблонами команды).
xargs объединяет входные строки с шаблоном команды для создания и запу-

ска новых полноценных команд, которые будем называть сгенерированными
командами.
Рассмотрим простой пример. Предположим, вы находитесь в каталоге с тремя
файлами:
$ ls -1
apple
banana
cantaloupe

Передадим список каталогов в xargs, чтобы он служил входными строками,
и wc -l в качестве шаблона команды:
$
3
4
1
8

ls -1 | xargs wc -l
apple
banana
cantaloupe
total

Как и было обещано, xargs применила шаблон команды wc -l к каждой из
входных строк, подсчитывая строки в каждом файле. Чтобы вывести те же три
файла с помощью cat, просто измените шаблон команды:
$ ls -1 | xargs cat

У этих примеров есть два существенных недостатка: фатальный и практический.
Фатальный недостаток заключается в том, что xargs может сделать что-то неправильно, если входная строка содержит специальные символы, например
пробелы. Надежное решение находится в разделе «Безопасность с помощью
find и xargs» на с. 151.
Практический недостаток заключается в том, что в данном примере не требуется xargs, можно решить те же задачи проще с помощью сопоставления файлов
с шаблоном:

150  Глава 7. Еще 11 способов запуска команды

$
3
4
1
8

wc -l *
apple
banana
cantaloupe
total

Зачем тогда использовать команду xargs? Ее мощь становится очевидной, когда
входные строки сложнее, чем простой список каталогов. Предположим, вы хотите
рекурсивно посчитать количество строк во всех файлах каталога и всех его подкаталогах, но только для исходных файлов Python с именами, оканчивающимися
на .py. Такой список путей к файлам легко создать с помощью команды find:
$ find . -type f -name \*.py -print
fruits/raspberry.py
vegetables/leafy/lettuce.py


Теперь xargs может применить шаблон команды wc -l к каждому пути к файлу,
создавая рекурсивный результат, который было бы трудно получить другим
способом. В целях безопасности заменим опцию -print на -print0, а xargs на
xargs -0 (см. врезку «Безопасность при использовании find и xargs» на с. 151):
$ find . -type f -name \*.py -print0 | xargs -0 wc -l
6 ./fruits/raspberry.py
3 ./vegetables/leafy/lettuce.py


Комбинируя find и xargs, можно дать возможность любой команде рекурсивно
выполняться с обходом всей файловой системы, затрагивая только те файлы и/
или каталоги, которые соответствуют указанным критериям (в некоторых случаях можно получить тот же эффект просто с помощью find, используя параметр
-exec, но xargs часто является более правильным решением).
Команда xargs имеет множество опций (см. man xargs), которые управляют тем,
как она создает и запускает сгенерированные команды. На мой взгляд, наиболее
важными (кроме -0) являются -n и -I. Параметр -n определяет, сколько аргументов
добавляется с помощью xargs к каждой сгенерированной команде (по умолчанию
добавляется столько аргументов, сколько позволят ограничения оболочки1):
$ ls | xargs echo
Уместить как можно больше входных строк:
apple banana cantaloupe carrot
echo apple banana cantaloupe carrot
$ ls | xargs -n1 echo Один аргумент в каждой команде echo:
apple echo apple
banana echo banana
cantaloupe echo cantaloupe
carrot echo carrot
1

Точное число зависит от ограничения длины строки в вашей системе Linux, см. man xargs.

Команда как строка  

$ ls | xargs -n2 echo
apple banana
cantaloupe carrot
$ ls | xargs -n3 echo
apple banana cantaloupe
carrot echo carrot

Два аргумента в каждой команде echo:
echo apple banana
echo cantaloupe carrot
Три аргумента в каждой команде echo:
echo apple banana cantaloupe

БЕЗОПАСНОСТЬ ПРИ ИСПОЛЬЗОВАНИИ FIND И XARGS
При объединении find и xargs используйте xargs -0 (ноль) для
защиты на случай неожиданных специальных символов во входных
строках. А для вывода применяйте find -print0:
$ find параметры... -print0 | xargs -0 параметры...

Обычно xargs ожидает, что входные строки будут разделены пробелами. А если сами входные строки содержат другие пробелы,
например имена файлов с пробелами в них? По умолчанию xargs
будет рассматривать эти пробелы как разделители ввода и обрабатывать неполные строки, выдавая неверные результаты. Например,
если входные данные для xargs содержат строку prickly pear.py,
xargs воспримет ее как две входные строки и, скорее всего, выведет ошибку:
prickly: No such file or directory
pear.py: No such file or directory

Поэтому используйте xargs -0, чтобы разделителем служил нулевой символ (ноль в ASCII). Нули редко появляются в тексте, поэтому они являются идеальными разделителями для входных строк.
Как разделить входные строки нулями вместо символов новой
строки? К счастью, у команды find есть возможность сделать это:
используйте -print0 вместо -print.
Команда ls, к сожалению, не может использовать ноль в качестве
разделителя, поэтому предыдущие простые примеры с ls небезопасны. Вы можете преобразовать символы новой строки в нули
с помощью команды tr:
$ ls | tr '\n' '\0' | xargs -0 ...

Или используйте псевдоним, который выводит список файлов
и каталогов с записями, разделенными нулями:
aliasls0="find . -maxdepth 1 -print0"

151

152  Глава 7. Еще 11 способов запуска команды

Параметр -I определяет место входных строк в сгенерированной команде. По
умолчанию они добавляются к шаблону команды, но вы можете настроить
их отображение в другом месте. После -I введите любую строку (по вашему
выбору), и она станет прототипом, указывающим, куда следует вставлять
входные строки:
$ ls | xargs -I XYZ echo XYZ is my favorite food
apple is my favorite food
banana is my favorite food
cantaloupe is my favorite food
carrot is my favorite food

XYZ в качестве прототипа

Строка XYZ расположена после команды echo , что перемещает входную
строку в начало каждой выходной строки. Обратите внимание, что параметр
-I ограничивает xargs одной входной строкой на сгенерированную команду. Изучите справочную страницу xargs, чтобы узнать, что еще вы можете
контролировать.

Длинные списки аргументов
xargs позволяет решать проблему чрезмерно длинных командных строк.
Предположим, что ваш текущий каталог содержит миллион файлов с именами от file1.txt до file1000000.txt, и вы пытаетесь удалить их путем сопоставления с шаблоном:
$ rm *.txt
bash: /bin/rm: Argument list too long

Шаблон *.txt вычисляется как строка из более чем 14 миллионов символов, что превышает ограничение Linux. Чтобы обойти его, передайте
список файлов в xargs для удаления. xargs разделит список файлов
на несколько команд rm. Сформируйте список файлов с помощью grep,
обрабатывая только имена файлов, заканчивающиеся на .txt, а затем передайте его в xargs:
$ ls | grep '\.txt$' | xargs rm

Это решение лучше, чем сопоставление с шаблоном файлов (ls *.txt),
которое приведет к той же ошибке Argument list too long. Еще лучше запустить find print0, как описано в разделе «Безопасность при использовании find и xargs» на с. 151:
$ find . -maxdepth 1 -name \*.txt -type f -print0 \
| xargs -0 rm

Способы, использующие управление процессами  

153

Способы, использующие управление процессами
Все обсуждавшиеся ранее команды выполняются в родительской оболочке.
Давайте рассмотрим несколько способов, которые ведут себя в этом отношении
иначе:
Фоновые команды
Возвращают приглашение командной строки и выполняются в фоновом
режиме.
Явные подоболочки
Могут быть запущены в середине составной команды.
Замена процесса
Заменяют родительскую оболочку.

Способ #9. Фоновое выполнение команды
До сих пор во всех способах, пока команда выполнялась, вы ждали, когда появится приглашение командной строки. Его появление означало, что команда
завершила работу. Но ждать этого не обязательно, особенно для команд, выполнение которых занимает много времени. Вы можете запускать команды особым
образом, чтобы они исчезали из поля зрения (в каком-то смысле), но продолжали
выполняться, немедленно освобождая текущую оболочку для других команд.
Этот метод называется фоновым выполнением команды (backgrounding). Если же
команда занимает оболочку, ее называют командой переднего плана (foreground).
Экземпляр оболочки одновременно запускает не более одной команды переднего
плана и любое количество фоновых команд.

Запуск команды в фоновом режиме
Чтобы запустить команду в фоновом режиме, просто добавьте амперсанд (&).
Оболочка отвечает сообщением, свидетельствующим, что команда запущена
в фоновом режиме, и выводит приглашение командной строки:
$ wc -c my_extremely_huge_file.txt & Подсчет символов в огромном файле
[1] 74931 Ответ оболочки
$

Затем вы можете продолжить выполнение команд переднего плана или других
фоновых команд в этой оболочке. Вывод фоновых команд может появиться

154  Глава 7. Еще 11 способов запуска команды

в любое время, даже когда вы печатаете. Если фоновая команда завершится
успешно, оболочка выведет сообщение Done:
59837483748 my_extremely_huge_file.txt
[1]+ Done
wc -c my_extremely_huge_file.txt

Если команда не выполнится, вы увидите сообщение о выходе с кодом возврата:
[1]+ Exit 1 wc -c my_extremely_huge_file.txt

Амперсанд является оператором списка, как && и ||:
$ command1 & command2 & command3 &
Все три команды
[1] 57351 выполняются фоном
[2] 57352
[3] 57353
$ command4 & command5 & echo hi Все команды, кроме echo,
[1] 57431 выполняются фоном
[2] 57432
hi

Приостановка и перевод команды в фоновый режим
Можно запустить команду переднего плана, а потом передумать и отправить
ее в фоновый режим. Нажмите Ctrl-Z, чтобы временно остановить выполнение
команды. В появившемся приглашении командной строки введите bg, чтобы
возобновить выполнение команды в фоновом режиме.

Задания и управление ими
Фоновые команды являются частью функции оболочки, называемой управлением заданиями. Она позволяет манипулировать запущенными командами,
например переводить их в фоновый режим, приостанавливать и возобновлять.
Задание — это единица работы оболочки, один экземпляр команды, выполняемой
в оболочке. Простые команды, конвейеры и условные списки — все это примеры
заданий, которые можно запускать из командной строки.
Задание — это больше, чем просто процесс Linux. Задание может состоять из
одного или нескольких процессов. Конвейер из шести программ, например,
представляет собой одно задание, включающее (как минимум) шесть процессов.
Задания — это конструкция оболочки. Linux отслеживает не задания, а только
лежащие в их основе процессы.
В оболочке может быть запущено одновременно несколько заданий. Каждое задание имеет положительный целочисленный идентификатор, называемый также

Способы, использующие управление процессами  

155

номером задания. Когда вы запускаете команду в фоновом режиме, оболочка печатает номер задания и идентификатор первого процесса, запущенного в задании.
В следующем примере номер задания равен 1, а идентификатор процесса — 74931:
$ wc -c my_extremely_huge_file.txt &
[1] 74931

Общие команды управления заданиями
Оболочка имеет встроенные команды для управления заданиями, перечисленные
в табл. 7.1. Рассмотрим наиболее распространенные операции управления заданиями. Для начала запустим команду sleep, которая ничего не делает (спит)
в течение заданного количества секунд, а затем завершает работу. Например,
sleep 10 спит в течение 10 секунд.

Таблица 7.1. Команды управления заданиями
Команда

Значение

bg

Переместить текущее приостановленное задание в фоновый режим

bg %n

Переместить приостановленное задание номер n в фоновый режим (пример: bg %1)

fg

Переместить текущее фоновое задание на передний план

fg %n

Переместить фоновое задание номер n на передний план (пример: fg %2)

kill %n

Завершить фоновое задание номер n (пример: kill %3)

jobs

Просмотр списка заданий оболочки

Запустим задание в фоновом режиме до его завершения:
$ sleep 20 & Запуск в фоновом режиме
[1] 126288
$ jobs Вывод списка заданий
[1]+ Running
sleep 20 &
$
...Завершение...
[1]+ Done
sleep 20

По завершении задания сообщение Done может не появиться до тех пор,
пока вы в очередной раз не нажмете Enter.

156  Глава 7. Еще 11 способов запуска команды

Запустим фоновое задание и переведем его на передний план:
$ sleep 20 &
[1] 126362
$ fg
sleep 20
...Завершение...
$

Запуск в фоновом режиме
Перемещение на передний план

Запустим задание переднего плана, приостановим его и вернем снова на передний план:
$ sleep 20
^Z
[1]+ Stopped sleep 20
$ jobs
[1]+ Stopped sleep 20
$ fg
sleep 20
...Завершение...
[1]+ Done sleep 20

Запуск задания на переднем плане
Прерывание выполнения
Вывод списка заданий
Перемещение на передний план

Запустим задание переднего плана и отправим его в фоновый режим:
$ sleep 20
^Z
[1]+ Stopped sleep 20
$ bg
[1]+ sleep 20 &
$ jobs
[1]+ Running sleep 20 &
$
...Завершение...
[1]+ Done sleep 20

Запуск в фоновом режиме
Прерывание выполнения
Перемещение в фоновый режим
Вывод списка заданий

Попробуем с несколькими фоновыми заданиями. Обратимся к заданию по его
номеру, которому предшествует знак процента (%1, %2 и т. д.):
$ sleep 100 &
[1] 126452
$ sleep 200 &
[2] 126456
$ sleep 300 &
[3] 126460
$ jobs
[1]
Running sleep 100 &
[2]- Running sleep 200 &
[3]+ Running sleep 300 &
$ fg %2
sleep 200

Запуск трех команд в фоновом режиме

Вывод списка заданий

Перемещение задания 2 на передний план

Способы, использующие управление процессами  

157

^Z Прерывание выполнения задания 2
[2]+ Stopped sleep 200
$ jobs Задание 2 приостановлено (stopped)
[1]
Running sleep 100 &
[2]+ Stopped sleep 200
[3]- Running sleep 300 &
$ kill %3 Завершение работы задания 3
[3]+ Terminated
sleep 300
$ jobs Задание 3 исчезло из списка
[1]- Running sleep 100 &
[2]+ Stopped sleep 200
$ bg %2
Возобновление приостановленного задания 2
[2]+ sleep 200 &

в фоновом режиме
$ jobs
Задание 2 снова запущено
[1]- Running sleep 100 &
[2]+ Running sleep 200 &
$

Вывод и ввод в фоновом режиме
Фоновая команда может использовать стандартный вывод, но иногда это может
произойти в самый неудобный момент. Что произойдет, если вы отсортируете
файл словаря Linux длиной 100 000 строк и зададите вывод на экран двух первых строк в фоновом режиме? Вначале оболочка печатает номер задания (1),
идентификатор процесса (81089) и приглашение к вводу:
$ sort /usr/share/dict/words | head -n2 &
[1] 81089
$

Когда задание завершится, оно выведет две строки, где бы ни находился курсор
в этот момент, например:
$ sort /usr/share/dict/words | head -n2 &
[1] 81089
$ A
A's

Нажмите Enter — и оболочка сообщит, что задание выполнено:
[1]+ Done sort /usr/share/dict/words | head -n2
$

Вывод на экран при выполнении фонового задания может появиться в любое
время. Чтобы избежать беспорядка, перенаправьте stdout в файл, а затем просмотрите его, когда вам будет удобно:
$ sort /usr/share/dict/words | head -n2 > /tmp/results &
[1] 81089

158  Глава 7. Еще 11 способов запуска команды

$
[1]+ Done sort /usr/share/dict/words | head -n2 > /tmp/results
$ cat /tmp/results
A
A's
$

Неожиданности случаются и тогда, когда фоновое задание пытается читать со
стандартного ввода. Оболочка приостанавливает задание, печатает сообщение
Stopped и ожидает ввода. Продемонстрируем это, запустив команду cat в фоновом
режиме без аргументов, чтобы она читала стандартный ввод:
$ cat &
[1] 82455
[1]+ Stopped cat

Задания не могут читать ввод в фоновом режиме, поэтому сначала переведем
его на передний план с помощью fg, а затем введем данные:
$ fg
cat
Here is some input
Here is some input


После ввода всех данных выполните одно из следующих действий:
Продолжайте выполнять команду на переднем плане, пока она не завершится.
Приостановите и снова запустите команду, нажав Ctrl-Z, а затем bg.
Завершите ввод с помощью Ctrl-D или завершите команду с помощью
Ctrl-C.

Советы по работе с фоновым режимом
Фоновый режим идеально подходит для команд, выполнение которых занимает
много времени, таких, например, как обработка текста во время длительных
сеансов редактирования, и программ, которые открывают собственные окна.
Например, программисты могут сэкономить много времени, приостанавливая
работу своего текстового редактора, вместо того чтобы выходить из него. Я видел,
как опытные инженеры правили код в текстовом редакторе, сохраняли результат
и закрывали редактор, тестировали код, затем перезапускали редактор и искали
место в коде, на котором они остановились. При такой организации процесса
они теряют 10–15 секунд на смену задания каждый раз, когда выходят из редактора. Если бы вместо этого они приостанавливали работу редактора (Ctrl-Z),
тестировали свой код и возобновляли работу редактора (fg), то избежали бы
ненужной траты времени.

Способы, использующие управление процессами  

159

Фоновый режим также отлично подходит для запуска последовательности команд с использованием условного списка. Если какая-либо команда
в списке завершается неудачно, остальные не будут выполняться и задание
заканчивается:
$ command1 && command2 && command3 &

Но будьте внимательны с командами, которые считывают ввод, так как они могут
приостановить выполнение текущего задания и ждать ввод!

Способ #10. Явные подоболочки
Каждый раз, когда мы запускаем простую команду, она выполняется в дочернем процессе, как мы видели в разделе «Родительский и дочерний процессы»
на с. 123. Подстановка команд и подстановка процессов создают подоболочки.
Однако бывают случаи, когда полезно явно запустить дополнительную подоболочку. Для этого просто заключим команду в круглые скобки, и она запустится
в подоболочке:
$ (cd /usr/local && ls)
bin etc games lib man sbin share
$ pwd
/home/smith cd /usr/local выполнено в подоболочке

Применительно ко всей команде этот метод не очень полезен, за исключением,
возможно, того, что нам не нужно запускать вторую команду cd для возврата
в предыдущий каталог. Однако если мы заключим в круглые скобки только часть
комбинированной команды, то получим интересные возможности. Типичным
примером является конвейер, который меняет каталог в середине команды. Предположим, мы загрузили архив package.tar.gz и хотим извлечь файлы. Команда
tar в этом случае выглядит так:
$ tar xvf package.tar.gz
Makefile
src/
src/defs.h
src/main.c


Извлечение файлов происходит в текущий каталог1. Но что делать, если мы
хотим извлечь их в другой каталог? Можно сначала перейти туда и запустить
tar (а затем вернуться), но также можно выполнить эту задачу с помощью
одной команды. Хитрость заключается в том, чтобы передать tar-данные
1

Предполагается, что tar-архив был создан с относительными, а не абсолютными путями,
что типично для скачиваемого программного обеспечения.

160  Глава 7. Еще 11 способов запуска команды

в подоболочку, которая выполняет операции с каталогами и запускает tar при
чтении из стандартного ввода1:
$ cat package.tar.gz | (mkdir -p /tmp/other && cd /tmp/other && tar xzvf -)

Этот метод также работает для копирования файлов из каталога dir1 в другой
существующий каталог dir2 с использованием двух процессов tar, один из которых записывает в стандартный вывод, а другой читает из стандартного ввода:
$ tar czf - dir1 | (cd /tmp/dir2 && tar xvf -)

Тот же метод может копировать файлы в существующий каталог на другом
хосте через SSH:
$ tar czf - dir1 | ssh myhost '(cd /tmp/dir2 && tar xvf -)'

КАКИЕ ИЗ ИЗУЧЕННЫХ СПОСОБОВ СОЗДАЮТ ПОДОБОЛОЧКИ?
Многие способы, описанные в этой главе, запускают подоболочку,
которая наследует родительскую среду (переменные и их значения)
плюс другой контекст оболочки, такой как псевдонимы. Другие
методы запускают только дочерний процесс. Самый простой способ
различить их — вычислить переменную BASH_SUBSHELL, которая
будет отличной от нуля для подоболочки и равна нулю в противном случае. Дополнительные сведения см. в разделе «Дочерние
оболочки vs подоболочки» на с. 128.
$
0
$
1
$
1
$
1
$
0

echo $BASH_SUBSHELL
Обычное выполнение
Не подоболочка
(echo $BASH_SUBSHELL)
Явная подоболочка
Подоболочка
echo $(echo $BASH_SUBSHELL) Подстановка команды
Подоболочка
cat echo hello
hello

Запустим дочернюю оболочку
Изменим приветствие командной строки
Запустим любую команду на ваш выбор

Теперь выполним команду exec и посмотрим, как завершит работу новая
оболочка:
Doomed> exec ls
animals.txt
$ A

ls заменяет дочернюю оболочку, запускается и завершает работу
Приветствие начальной (родительской) оболочки

Запуск команды exec может быть фатальным
Если вы запустите exec в оболочке, оболочка после этого закроется. Если
оболочка была запущена в окне терминала, терминал закроется. Если оболочка была оболочкой входа в систему, вы выйдете из системы.

Зачем вообще запускать exec? Одна из причин — чтобы экономить ресурсы, не
запуская второй процесс. Сценарии оболочки иногда используют эту оптимизацию, запуская exec для последней команды в сценарии. Если сценарий запускается много раз (скажем, миллионы или миллиарды выполнений), экономия
может оказаться оправданной.
Также у команды exec есть вторая функциональность — она может переназначать stdin, stdout и/или stderr для текущей оболочки. Это наиболее применимо
в сценариях оболочки. Как, например, в следующем довольно простом сценарии,
который печатает информацию в файл /tmp/outfile:
#!/bin/bash
echo "My name is $USER" > /tmp/outfile
echo "My current directory is $PWD" >> /tmp/outfile

162  Глава 7. Еще 11 способов запуска команды

echo "Guess how many lines are in the file /etc/hosts?" >> /tmp/outfile
wc -l /etc/hosts >> /tmp/outfile
echo "Goodbye for now" >> /tmp/outfile

Вместо перенаправления вывода каждой команды в /tmp/outfile по отдельности
используйте exec для перенаправления stdout в /tmp/outfile для всего скрипта.
Последующие команды могут использовать стандартный вывод:
#!/bin/bash
# Перенаправление вывода для всего скрипта
exec > /tmp/outfile2
# Все последующие команды печатаются в /tmp/outfile2
echo "My name is $USER"
echo "My current directory is $PWD"
echo "Guess how many lines are in the file /etc/hosts?"
wc -l /etc/hosts
echo "Goodbye for now"

Запустите этот сценарий и проверьте файл /tmp/outfile2, чтобы увидеть результаты:
$ cat /tmp/outfile2
My name is smith
My current directory is /home/smith
Guess how many lines are in the file /etc/hosts?
122 /etc/hosts
Goodbye for now

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

Резюме
Теперь вы знаете 13 способов выполнения команды — 11 из этой главы плюс
простые команды и конвейеры. В табл. 7.2 рассматриваются некоторые распространенные варианты использования различных методов.

Таблица 7.2. Распространенные идиомы для запуска команд
Задача

Решение

Отправка stdout из одной программы
в stdin другой

Конвейеры

Вставка вывода (stdout) в команду

Подстановка команды

Резюме  163

Задача

Решение

Предоставление вывода (stdout) команде,
которая читает не из stdin, а из файла

Подстановка процесса

Выполнение одной строки как команды

bash -c, или канал с участием bash

Вывод нескольких команд в stdout и их
выполнение

Конвейер с участием bash

Выполнение множества похожих команд
подряд

xargs или создание команд в виде строк и передача
их в bash

Управление командами, которые зависят от
успеха друг друга

Условные списки

Запуск нескольких команд одновременно

Фоновый режим работы

Одновременный запуск нескольких команд,
которые зависят от успеха друг друга

Условные списки в фоновом режиме

Запуск одной команды на удаленном хосте

Запуск ssh host command

Изменение каталога в середине конвейера

Явные подоболочки

Выполнение команды позже

Безусловный список с командой sleep, за которым
следует основная команда

Перенаправление в/из защищенных файлов

Запуск sudo bash -c "command > file"

Следующие две главы научат вас комбинировать эти методы для эффективного
решения поставленных задач.

ГЛАВА 8

Создание дерзких однострочников

Помните эту длинную запутанную команду из предисловия?
$ paste &2 echo "Usage: $PROGRAM string"
exit 1

fi
searchstring="$1"
# Сохранить расшифрованный текст в переменной
decrypted=$(gpg -d -q "$DATABASE")
# Искать точные совпадения в третьем столбце
match=$(echo "$decrypted" | awk '$3~/^'$searchstring'$/')
# Если строка поиска не соответствует ключу, найти все совпадения
if [ -z "$match" ]; then
match=$(echo "$decrypted" | awk "/$searchstring/")
fi
# Если совпадений по-прежнему нет, вывести сообщение об ошибке и выйти
if [ -z "$match" ]; then
>&2 echo "$PROGRAM: no matches for '$searchstring'"
exit 1
fi
# Вывод совпадений
echo "$match"

Теперь сценарий отображает пароли из зашифрованного файла:
$ pman dropbox
Passphrase: xxxxxxxx
ssmith fake2
dropbox dropbox.com account for work
$ pman drop
Passphrase: xxxxxxxx
ssmith fake2
dropbox dropbox.com account for work
birdy
fake5
dropbox2 dropbox.com account for home

Теперь у нас есть полноценный менеджер паролей. Некоторые заключительные шаги:
Когда вы убедитесь, что можете надежно расшифровывать файл vault.gpg,
удалите исходный файл vault.
При желании замените поддельные пароли реальными. См. раздел
«Прямое редактирование зашифрованных файлов» на с. 196 с рекомендациями по редактированию зашифрованного текстового файла.
Не забывайте про комментарии в хранилище паролей — строки, начинающиеся со знака решетки (#), — чтобы вы могли делать примечания
к записям. Обновите сценарий, чтобы передать расшифрованное содержимое команде grep -v. Это позволит отфильтровать строки, начинающиеся со знака решетки:
decrypted=$(gpg -d -q "$DATABASE" | grep -v '^#')

Печать паролей в стандартный вывод — не очень хорошая практика с точки
зрения безопасности. В разделе «Улучшение работы диспетчера паролей»
на с. 216 этот сценарий будет доработан для копирования и вставки паролей
вместо их вывода на экран.

196  Глава 9. Использование текстовых файлов

ПРЯМОЕ РЕДАКТИРОВАНИЕ ЗАШИФРОВАННЫХ ФАЙЛОВ
Чтобы изменить зашифрованный файл, наиболее прямолинейным,
трудоемким и небезопасным методом является расшифровка файла, его редактирование и повторное шифрование.
$ cd ~/etc
$ gpg vault.gpg Расшифровка
Passphrase: xxxxxxxx
$ emacs vault Использование текстового
редактора
$ gpg -e -r your_email_address vault
Шифрование
$ rm vault

Для упрощения редактирования файла vault.gpg и в Emacs, и в Vim
есть режимы редактирования файлов, зашифрованных с помощью
GnuPG. Начните с добавления следующей строки в файл конфигурации bash и применения его ко всем связанным оболочкам:
export GPG_TTY=$(tty)

Для Emacs настройте встроенный пакет EasyPG. Добавьте следующие строки в файл конфигурации $HOME/.emacs и перезапустите
Emacs (замените строку GnuPG ID here адресом электронной почты,
связанным с вашим ключом, например smith@example.com):
(load-library "pinentry")
(setq epa-pinentry-mode 'loopback)
(setq epa-file-encrypt-to "GnuPG ID here")
(pinentry-start)

После этого при редактировании зашифрованного файла Emacs
запросит ваш пароль и расшифрует файл в буфер для редактирования. При сохранении Emacs шифрует содержимое буфера.
Для Vim попробуйте плагин vim-gnupg (https://oreil.ly/mnwYc) и добавьте следующие строки в файл конфигурации $HOME/.vimrc:
let g:GPGPreferArmor=1
let g:GPGDefaultRecipients=["GnuPG ID here"]

Подумайте о создании псевдонима для удобного редактирования
хранилища паролей, используя прием из раздела «Редактируйте
часто используемые файлы с помощью псевдонима» на с. 74:
alias pwedit="$EDITOR $HOME/etc/vault.gpg"

Резюме  197

Резюме
Пути к файлам, имена доменов, коды городов и учетные данные для входа — это
лишь несколько примеров данных, которые удобны для обработки в структурированном текстовом файле. Есть много других возможностей:
Ваши музыкальные файлы — используйте команду Linux, например
id3tool, для извлечения информации ID3 из файлов MP3 и помещения
ее в файл.
Контакты на вашем мобильном устройстве — используйте приложение
для экспорта контактов в формат CSV, загрузите их в облачное хранилище, а затем загрузите на свой Linux-компьютер для обработки.
Ваши оценки в школе — используйте awk для отслеживания среднего
балла.
Список просмотренных фильмов или прочитанных книг с дополнительными данными — рейтингами, авторами, актерами и т. д.
Таким образом, вы можете создать целую систему команд, связанных с работой
и отдыхом и экономящих ваше время. Перспективы ограничены только вашим
воображением.

ЧАСТЬ 3

Дополнительные плюсы

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

ГЛАВА 10

Эффективное использование
клавиатуры

В самый обычный день на обычном компьютере с Linux у вас может быть открыто множество окон: веб-браузеры, текстовые редакторы, среды разработки
программного обеспечения, музыкальные проигрыватели, видеоредакторы,
виртуальные машины и т. д. Некоторые приложения ориентированы на графический интерфейс, например программы для рисования, и приспособлены для
работы с мышью или трекболом. Другие более ориентированы на клавиатуру,
например командная оболочка внутри терминальной программы. Типичный
пользователь Linux может переходить с клавиатуры на мышь и обратно десятки (или даже сотни) раз в час. Каждое такое переключение требует времени
и замедляет работу. Если вы сможете уменьшить количество переключений, то
станете работать более эффективно.
В этой главе рассказывается о том, как проводить больше времени за клавиатурой и меньше пользоваться мышью. Десять пальцев, нажимающих на сотню
клавиш, обычно более быстры, чем пара пальцев на мыши. Речь не только об
использовании горячих клавиш — я уверен, что вы найдете информацию о них
и без этой книги (хотя некоторые сочетания все-таки будут приведены). Я говорю о подходе к ускорению некоторых повседневных задач, которые по своей
сути требуют использования мыши: работа с окнами, получение информации
из интернета, копирование и вставка с помощью буфера обмена.

Работа с окнами
В этом разделе я поделюсь советами по эффективному запуску окон, особенно
окон командной оболочки (терминалов) и браузера.

Работа с окнами  

201

Мгновенный запуск оболочек и браузера
Большинство сред рабочего стола Linux, такие как GNOME, KDE Plasma, Unity
и Cinnamon, позволяют назначить горячие клавиши — специальные сочетания
клавиш, которые запускают команды или выполняют другие операции. Настоятельно рекомендуется определить сочетания клавиш для следующих распространенных операций:
Запуск терминальной программы (окна командной оболочки).
Запуск окна веб-браузера.
После этого вы сможете мгновенно открывать терминал или браузер в любой
момент, независимо от того, какое приложение вы используете1. Для настройки
необходимо знать следующее:
Команда, запускающая предпочитаемую вами терминальную программу
Самые популярные — gnome-terminal, konsole и xterm.
Команда, запускающая предпочитаемый вами браузер
Самые популярные — firefox, google-chrome и opera.
Способ определения собственного сочетания клавиш
Инструкции различаются для каждого типа окружения рабочего стола
и могут меняться от версии к версии, поэтому лучше уточнить их в интернете. Выполните поиск по имени вашего окружения рабочего стола
с ключевыми словами «определение сочетания клавиш» («define keyboard
shortcut»).
На своем компьютере я назначил сочетание клавиш Ctrl-Windows-T для запуска
терминала konsole и Ctrl-Windows-C для запуска google-chrome.

Рабочие каталоги
Когда вы запускаете новый экземпляр оболочки с помощью сочетания
клавиш в среде рабочего стола, он является дочерним по отношению
к вашей оболочке входа в систему. Его текущий каталог — ваш домашний
каталог (если только вы не настроили его иначе).
Сравните это с открытием новой оболочки из вашей терминальной программы, явно запустив, например, gnome-terminal или xterm в командной
1

Если только вы не работаете с приложением, которое перехватывает все нажатия клавиш,
например с виртуальной машиной в отдельном окне.

202  Глава 10. Эффективное использование клавиатуры

строке либо используя меню вашей терминальной программы. В этом
случае новая оболочка является потомком оболочки этого терминала. Его
текущий каталог — такой же, как у его родителя, который может не быть
вашим домашним каталогом.

Одноразовые окна
Предположим, вы используете несколько приложений, и вдруг вам нужна оболочка для выполнения одной команды. Многие пользователи хватают мышь
и ищут в открытых окнах работающий терминал. Не делайте этого — вы просто
теряете время. Откройте новый терминал с помощью горячих клавиш, запустите
команду и сразу же выйдите из терминала.
Если у вас назначены горячие клавиши для запуска терминальных программ
и окон браузера, смело открывайте и не забывайте закрывать эти окна. Не оставляйте терминалы и окна браузера открытыми на долгое время! Я называю эти
недолговечные окна одноразовыми — они быстро открываются, используются
несколько секунд и затем закрываются.
Есть смысл оставить несколько оболочек открытыми в течение длительного
времени, если вы разрабатываете программное обеспечение или выполняете
другую длительную работу, но одноразовые окна терминала идеально подходят
для команд, которые могут понадобиться один раз в течение дня. Часто быстрее
открыть новый терминал, чем искать на экране существующий. Не спрашивайте себя: «Где нужное окно терминала?» — и не теряйте время на поиск. Лучше
создайте новое окно и закройте его? после того как оно выполнило свою задачу.
Тот же принцип действует для окон веб-браузера. Вы когда-нибудь поднимали
голову после долгого дня работы в Linux и обнаруживали, что в вашем браузере
всего одно окно и 83 открытые вкладки? Это симптом неиспользования одноразовых окон. Откройте одно, просмотрите веб-страницу, а потом закройте его.
Нужно вернуться на страницу позже? Обратитесь к истории браузера.

Горячие клавиши в браузере
Поскольку мы заговорили об окнах браузера, убедитесь, что знаете наиболее
важные сочетания клавиш из табл. 10.1. Если ваши руки уже находятся на
клавиатуре и вы хотите перейти на новый веб-сайт, зачастую быстрее нажать
Ctrl-L, чтобы перейти к адресной строке, или Ctrl-T, чтобы открыть вкладку, чем
двигать указатель мыши.

Работа с окнами  

203

Таблица 10.1. Наиболее важные горячие клавиши для Firefox, Google Chrome и Opera
Действие

Горячие клавиши

Открыть новое окно

Ctrl-N

Открыть новое окно в режиме инкогнито

Ctrl-Shift-P (Firefox), Ctrl-Shift-N (Chrome и Opera)

Открыть новую вкладку и перейти на нее

Ctrl-T

Закрыть активную вкладку

Ctrl-W

Перейти на следующую открытую вкладку Ctrl-Tab (переход вперед) и Ctrl-Shift-Tab (переход назад)
Перейти на адресную строку

Ctrl-L (или Alt-D, или F6)

Искать текст на активной вкладке

Ctrl-F

Открыть историю

Ctrl-H

Переключение окон и рабочих столов
Когда ваш рабочий стол заполнен окнами, как быстро найти нужное? Вы можете водить указателем мыши и пробираться сквозь тернии к нужному окну, но
быстрее использовать сочетание клавиш Alt-Tab. Продолжайте нажимать Alt-Tab,
и вы последовательно просмотрите все окна на рабочем столе. Когда дойдете
до нужного окна, отпустите клавиши — и это окно окажется в фокусе и будет
готово к использованию. Чтобы прокрутить в обратном направлении, нажмите
Alt-Shift-Tab.
Чтобы просмотреть все окна на рабочем столе, принадлежащие одному
и тому же приложению, например все окна Firefox, нажмите Alt-` (обратная
кавычка — клавиша над Tab). Чтобы вернуться, добавьте нажатие клавиши
Shift (Alt-Shift-`).
Когда вы научились переключать окна, пришло время поговорить о переключении рабочих столов. Если вы используете только один рабочий стол (также
называемый рабочим пространством или виртуальным рабочим столом), значит
упускаете отличный способ улучшить организацию своей работы в Linux. Вместо
одного у вас может быть четыре, шесть или более рабочих столов, каждый со
своими окнами, и вы можете переключаться между ними.

204  Глава 10. Эффективное использование клавиатуры

На рабочем компьютере под управлением Ubuntu Linux с KDE Plasma я запускаю шесть виртуальных рабочих столов и назначаю им разные цели. Рабочий
стол № 1 — это мое основное рабочее пространство с электронной почтой
и браузером, № 2 — для семейных задач, № 3 — это место, где я запускаю
виртуальные машины VMware, № 4 — для написания книг, подобных этой,
а № 5–6 — для разнообразных разовых или срочных задач. Такая группировка рабочих столов позволяет мне быстро и легко находить открытые окна из
разных приложений.
Каждое окружение рабочего стола Linux, такое как GNOME, KDE Plasma,
Cinnamon и Unity, имеет свой собственный способ реализации виртуальных
рабочих столов, но все они предоставляют механизм для переключения между
ними. Я рекомендую определить сочетания клавиш в окружении вашего рабочего
стола, чтобы быстро переходить на нужный рабочий стол. На своем компьютере
я использую сочетания клавиш от Windows + F1 до Windows + F6 для перехода
к рабочим столам с № 1 по № 6 соответственно.
Существует множество других стилей работы с рабочими столами и окнами.
Некоторые люди используют один рабочий стол для каждого приложения:
терминала, просмотра веб-страниц, обработки текстов и т. д. Пользователи компактных ноутбуков часто открывают только одно окно в полноэкранном режиме
на каждом рабочем столе. Найдите стиль, который вам подходит, главное, чтобы
он способствовал быстрой и эффективной работе.

Доступ в интернет из командной строки
Браузеры с управлением типа «укажи и щелкни» почти синонимичны интернету,
но вы также можете получать доступ к веб-сайтам из командной строки Linux,
что иногда бывает полезно.

Запуск окон браузера из командной строки
Возможно, вы привыкли запускать веб-браузер, щелкая мышкой или касаясь
значка, но вы также можете делать это из командной строки Linux. Если браузер
еще не запущен, добавьте символ амперсанда, чтобы запустить его в фоновом
режиме и вернуть приглашение командной строки:
$ firefox &
$ google-chrome &
$ opera &

Доступ в интернет из командной строки  

205

Если браузер уже запущен, уберите амперсанд. Такая команда указывает существующему экземпляру браузера открыть новое окно или вкладку, после чего
завершает работу и возвращает приглашение командной строки.
Команда запуска браузера в фоновом режиме может печатать диагностические сообщения и загромождать окно оболочки. Чтобы предотвратить
это, перенаправьте весь вывод при первом запуске браузера в /dev/null.
Например:
$ firefox &> /dev/null &

Чтобы открыть браузер и перейти по URL-адресу из командной строки, укажите
URL-адрес в качестве аргумента:
$ firefox https://oreilly.com
$ google-chrome https://oreilly.com
$ opera https://oreilly.com

По умолчанию предыдущие команды открывают новую вкладку и переходят на
нее. Если вместо этого надо заставить их открыть новое окно, добавьте параметр:
$ firefox --new-window https://oreilly.com
$ google-chrome --new-window https://oreilly.com
$ opera --new-window https://oreilly.com

Чтобы открыть приватное окно или окно браузера в режиме инкогнито, добавьте
соответствующий параметр командной строки:
$ firefox --private-window https://oreilly.com
$ google-chrome --incognito https://oreilly.com
$ opera --private https://oreilly.com

Приведенные выше команды могут показаться трудоемкими в наборе, но вы
можете повысить свою эффективность, определив псевдонимы для сайтов,
которые часто посещаете:
# Поместите в файл конфигурации оболочки и используйте:
alias oreilly="firefox --new-window https://oreilly.com"

Аналогичным образом, если у вас есть файл, содержащий интересующий URLадрес, извлеките этот адрес с помощью grep , cut или других команд Linux
и передайте его в браузер, используя подстановку команд. Вот пример работы
с файлом, содержащим разделенные табуляциями два столбца:

206  Глава 10. Эффективное использование клавиатуры

$ cat urls.txt
duckduckgo.com My search engine
nytimes.com My newspaper
spotify.com My music
$ grep music urls.txt | cut -f1
spotify.com
$ google-chrome https://$( grep music urls.txt | cut -f1 )

Переход на сайт

Или предположим, что вы отслеживаете ожидаемые посылки с помощью файла
с номерами треков:
$ cat packages.txt
1Z0EW7360669374701 UPS Shoes
568733462924 FedEx Kitchen blender
9305510823011761842873 USPS Care package from Mom

Сценарий в листинге 10.1 открывает страницы отслеживания для отправителей
(UPS, FedEx или почтовая служба США), добавляя номера отслеживания к соответствующим URL-адресам.
Листинг 10.1. Сценарий track-it, открывающий страницу отслеживания
грузоотправителей
#!/bin/bash
PROGRAM=$(basename $0)
DATAFILE=packages.txt
# Выберите браузер: firefox, opera или google-chrome
BROWSER="opera"
errors=0
cat "$DATAFILE" | while read line; do
track=$(echo "$line" | awk '{print $1}')
service=$(echo "$line" | awk '{print $2}')
case "$service" in
UPS)
$BROWSER "https://www.ups.com/track?tracknum=$track" &
;;
FedEx)
$BROWSER "https://www.fedex.com/fedextrack/?trknbr=$track" &
;;
USPS)
$BROWSER "https://tools.usps.com/go/TrackConfirmAction?tLabels=$track" &
;;
*)
>&2 echo "$PROGRAM: Unknown service '$service'"
errors=1
;;
esac
done
exit $errors

Доступ в интернет из командной строки  

207

Получение HTML-страниц с помощью curl и wget
Не только веб-браузеры посещают веб-сайты. Программы curl и wget могут
загружать веб-страницы и другой веб-контент без использования браузера. По
умолчанию curl выводит в stdout, а wget сохраняет вывод в файл:
$ curl https://efficientlinux.com/welcome.html
Welcome to Efficient Linux.com!
$ wget https://efficientlinux.com/welcome.html
--2021-10-27 20:05:47-- https://efficientlinux.com/
Resolving efficientlinux.com (efficientlinux.com)...
Connecting to efficientlinux.com (efficientlinux.com)...

2021-10-27 20:05:47 (12.8 MB/s) - 'welcome.html' saved [32/32]
$ cat welcome.html
Welcome to Efficient Linux.com!

Некоторые сайты не поддерживают выгрузку данных с помощью wget
и curl. В таких случаях обе команды могут маскироваться под браузер.
Просто укажите каждой программе изменить свой пользовательский
агент — строку, которая идентифицирует веб-клиент для веб-сервера.
Удобный пользовательский агент — «Mozilla»:
$ wget -U Mozilla url
$ curl -A Mozilla url

И у wget, и у curl есть множество опций и функций, которые вы можете найти на
их справочных страницах. А пока давайте посмотрим, как включить эти команды
в дерзкие однострочники. Предположим, что на веб-сайте Effectivelinux.com есть
каталог images, содержащий файлы с 1.jpg по 20.jpg, и вы хотите их загрузить.
Их URL-адреса:
https://efficientlinux.com/images/1.jpg
https://efficientlinux.com/images/2.jpg
https://efficientlinux.com/images/3.jpg


Неэффективно посещение каждого URL-адреса по одному и последовательная
загрузка изображений (поднимите руку, если вы когда-либо делали подобное!).
Лучший способ — использовать wget. Сгенерируйте URL-адреса с помощью
seq и awk:
$ seq 1 20 | awk '{print "https://efficientlinux.com/images/" $1 ".jpg"}'
https://efficientlinux.com/images/1.jpg
https://efficientlinux.com/images/2.jpg
https://efficientlinux.com/images/3.jpg


208  Глава 10. Эффективное использование клавиатуры

Затем добавьте строку wget в программу awk и передайте полученные команды
в bash для выполнения:
$ seq 1 20 \
| awk '{print " wget https://efficientlinux.com/images/" $1 ".jpg"}' \
| bash

В качестве альтернативы используйте xargs для создания и выполнения команд
wget:
$ seq 1 20 | xargs -I@ wget https://efficientlinux.com/images/@.jpg

Вариант с командой xargs предпочтителен, если ваши команды wget содержат
специальные символы. Решение, использующее канал в bash (pipe to bash),
заставит оболочку вычислять эти символы (чего вы не хотите), а решение
с xargs — нет.
Пример выше был надуманным, потому что имена файлов изображений, как
правило, схожи. В более реалистичном примере вы можете загрузить все изображения с веб-страницы с помощью curl, пропустив ее через хитроумную
последовательность команд, чтобы изолировать URL-адреса изображений, по
одному на строку, а затем применяя один из методов, которые показаны выше:
curl URL | ...какой-то умный конвейер... | xargs -n1 wget

Обработка кода HTML с помощью HTML-XML-utils
Если вы знакомы с HTML и CSS, то сможете анализировать исходный HTMLкод веб-страниц из командной строки. Иногда это более эффективно, чем ручное
копирование и вставка фрагментов веб-страницы из окна браузера. Удобным
набором инструментов является HTML-XML-utils, который доступен во многих
дистрибутивах Linux от World Wide Web Consortium (https://www.w3.org/Tools/
HTML-XML-utils/). Общий порядок действий:
1.
2.
3.
4.

Захватите исходный код HTML с помощью curl (или wget).
Оптимизируйте формат HTML с помощью hxnormalize.
Определите CSS-селекторы для HTML-элементов.
Используйте hxselect, чтобы изолировать значения, и передайте вывод
для последующей обработки.

Давайте дополним пример из раздела «Создание базы данных телефонных кодов» на с. 188, чтобы создать файл areacodes.txt с кодами городов. Для вашего
удобства создана HTML-таблица кодов городов (рис. 10.1), которую вы можете
загрузить и обработать.

Доступ в интернет из командной строки  

209

Рис. 10.1. Таблица кодов городов на https://efficientlinux.com/areacodes.html
Вначале обработаем исходный HTML-код с помощью curl, используя параметр
-s для подавления экранных сообщений. Направим вывод команде hxnormalize -x
для очистки. Затем передадим его в less, чтобы просмотреть вывод поэкранно:
$ curl -s https://efficientlinux.com/areacodes.html \
| hxnormalize -x \
| less




Area code test


Таблица HTML, показанная в листинге 10.2, имеет CSS ID #ac, а ее три столбца
(код города —Area code, штат — State и местоположение — Location) используют
классы CSS ac, state и cities соответственно.
Листинг 10.2. Часть HTML-кода таблицы на рис. 10.1



Area code
State
Location




201

210  Глава 10. Эффективное использование клавиатуры

NJ
Hackensack, Jersey City





Запустим hxselect, чтобы извлечь данные кода города из каждой ячейки таблицы,
и укажем параметр -c, чтобы исключить теги td из вывода. Выведем на экран
результаты в виде одной строки с полями, разделенными символом @, используя
опцию -s1 (символ @ выбран для улучшения читаемости):
$ curl -s https://efficientlinux.com/areacodes.html \
| hxnormalize -x \
| hxselect -c -s@ '#ac .ac, #ac .state, #ac .cities'
201@NJ@Hackensack, Jersey City@202@DC@Washington@203@CT@New Haven, Stamford@...

Направим вывод в sed, чтобы превратить эту длинную строку в три колонки,
разделенных табуляцией.
Теперь нам требуется регулярное выражение со следующей структурой:
1. Код города, состоящий из цифр, [0-9]*.
2. Символ @.
3. Аббревиатура штата, состоящая из двух заглавных букв из диапазона
[A-Z].
4. Символ @.
5. Название города — любой текст, не содержащий символа @, ( [^@]*).
6. Символ @.
Объединим все части, чтобы получить следующее регулярное выражение:
[0-9]* @ [A-Z][A-Z] @ [^@]* @

Запишем код города, штата и название города в виде трех подвыражений, обозначив их символами \. Теперь у нас есть полное регулярное выражение для sed:
\( [0-9]* \)@\( [A-Z][A-Z] \)@\( [^@]* \)@

Для строки замены sed укажем три подвыражения, разделенные символами
табуляции и оканчивающиеся символами новой строки, что соответствует
формату файла areacodes.txt:
\1\t\2\t\3\n
1

В этом примере используются три селектора CSS, но некоторые старые версии hxselect
могут обрабатывать только два. Если ваша hxselect имеет этот недостаток, загрузите
последнюю версию на странице World Wide Web Consortium (https://www.w3.org/Tools/
HTML-XML-utils/) и выполните сборку с помощью команды configure && make.

Доступ в интернет из командной строки  

211

Объединим предыдущее регулярное выражение и строку замены, чтобы создать
sed-сценарий:
s/ \([0-9]*\)@\([A-Z][A-Z]\)@\([^@]*\)@ / \1\t\2\t\3\n /g

Готовая команда использует данные файла areacodes.txt:
$ curl -s https://efficientlinux.com/areacodes.html \
| hxnormalize -x \
| hxselect -c -s'@' '#ac .ac, #ac .state, #ac .cities' \
| sed 's/\([0-9]*\)@\([A-Z][A-Z]\)@\([^@]*\)@/\1\t\2\t\3\n/g'
201 NJ Hackensack, Jersey City
202 DC Washington
203 CT New Haven, Stamford


ОБРАБОТКА ДЛИННЫХ РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ
Если ваши sed-сценарии становятся слишком длинными, то они
выглядят как случайный набор символов:
s/\([0-9]*\)@\([A-Z][A-Z]\)@\([^@]*\)@/\1\t\2\t\3\n/g

Постарайтесь разделить их. Сохраните части регулярного выражения в нескольких переменных оболочки и объедините переменные
позже, как в следующем сценарии:
# Три части регулярного выражения.
# Используем одинарные кавычки, чтобы предотвратить вычисление
# выражения оболочкой
areacode='\([0-9]*\)'
state='\([A-Z][A-Z]\)'
cities='\([^@]*\)'
# Объединяем три части, разделенные символами @.
# Используем двойные кавычки, чтобы позволить оболочке вычислить
# переменную
regexp="$areacode@$state@$cities@"
# Строка для замены
# Используем одинарные кавычки, чтобы предотвратить вычисление
# выражения оболочкой
replacement='\1\t\2\t\3\n'
# sed-сценарий стал проще для восприятия:
# s/$regexp/$replacement/g
# Запускаем полную команду:
curl -s https://efficientlinux.com/areacodes.html \
| hxnormalize -x \
| hxselect -c -s'@' '#ac .ac, #ac .state, #ac .cities' \
| sed "s/$regexp/$replacement/g"

212  Глава 10.Эффективное использование клавиатуры

Получение и отображение содержимого веб-сайтов
с помощью текстового браузера
При получении данных из интернета в командной строке вам может понадобиться не HTML-код веб-страницы, а визуализированная версия. Визуализированный текст легче анализируется. Для этого используйте текстовый
браузер, такой как lynx или links . Текстовые браузеры отображают вебстраницы в урезанном формате без изображений и других модных функций.
На рис. 10.2 показана страница кодов городов из предыдущего раздела, отображаемая с помощью lynx.

Рис. 10.2. Отображение страницы https://efficientlinux.com/areacodes.html в lynx
lynx и links загружают веб-страницу с параметром -dump:
$ lynx -dump https://efficientlinux.com/areacodes.html > tempfile
$ cat tempfile
Area code test
Area code State
Location
201
NJ
Hackensack, Jersey City
202
DC
Washington
203
CT
New Haven, Stamford


Управление буфером обмена из командной строки  

213

lynx и links отлично подходят для проверки ссылок, когда вы не уверены в их происхождении. Эти текстовые браузеры не поддерживают
JavaScript и не отображают изображения, поэтому они менее уязвимы для
атак (конечно, они не гарантируют безопасность, поэтому действуйте на
свой страх и риск).

Управление буфером обмена из командной строки
Каждый современный программный пакет, имеющий меню Правка (Edit), содержит операции вырезания, копирования и вставки для переноса содержимого
в системный буфер обмена и из него. Возможно, вы знаете сочетания клавиш для
этих операций. Но знаете ли вы, что можете обрабатывать содержимое буфера
обмена прямо из командной строки?
Сначала немного предыстории: операции копирования и вставки в Linux
являются частью более общего механизма, называемого X-буферами обмена
(X selections]. Буфер обмена — это общее название для места нахождения скопированного содержимого, например системного буфера обмена. X — это название
оконной системы Linux.
Большинство построенных на X окружений рабочего стола Linux, таких как
GNOME, Unity, Cinnamon и KDE Plasma, поддерживают два варианта буфера
обмена1. Во-первых, это системный буфер обмена (clipboard), и он работает так
же, как буфер обмена в других операционных системах. Когда вы выполняете
операции вырезания или копирования в приложении, содержимое помещается
в буфер обмена, и затем вы извлекаете его с помощью операции вставки. Менее
знаком пользователям первичный буфер обмена (primary selection). Когда вы
выбираете текст в определенных приложениях, он записывается в первичный
буфер обмена, даже если вы не запустили операцию копирования. Примером
может служить выделение текста в окне терминала с помощью мыши. Этот текст
автоматически записывается в первичный буфер обмена.
Если вы подключаетесь к хосту Linux удаленно с помощью SSH или подобных программ, копирование/вставка обычно выполняются локальным
компьютером, а не буфером обмена на удаленном хосте Linux.

1

На самом деле существуют три буфера обмена, но один из них, называемый вторичным
(secondary selection), редко используется в современных окружениях рабочего стола.

214  Глава 10. Эффективное использование клавиатуры

В таблице 10.2 перечислены операции с мышью и клавиатурой для доступа
к буферам обмена в терминалах GNOME (gnome-terminal) и KDE Konsole
(konsole). Если вы используете другую терминальную программу, проверьте,
есть ли в ее меню Правка (Edit) операции, эквивалентные копированию (Copy)
и вставке (Paste).

Таблица 10.2. Доступ к буферам обмена в терминальных программах
Действие

Системный буфер обмена

Первичный буфер обмена

Копирование мышью

Откройте меню правой кноп- Нажмите левую кнопку и переместите или
ки и выберите пункт Copy
дважды нажмите, чтобы выбрать текущее
слово, либо нажмите трижды, чтобы выбрать текущую строку

Вставка мышью

Откройте меню правой кноп- Нажмите среднюю кнопку мыши (обычно
ки и выберите пункт Paste это колесо прокрутки)

Копирование с клавиатуры Ctrl-Shift-C



Вставка с клавиатуры,

Ctrl-Shift-V или Ctrl-Shift- Shift-Insert
Insert

Вставка с клавиатуры,

Ctrl-Shift-V или ShiftInsert

gnome-terminal
konsole

Ctrl-Shift-Insert

Подключение буферов обмена к stdin и stdout
В Linux есть команда xclip, которая соединяет X-буферы обмена со stdin и stdout.
Благодаря ей можно вставлять операции копирования и вставки в конвейеры
и другие составные команды. Например, можно скопировать текст в приложение
следующим образом:
1.
2.
3.
4.

Запустить команду Linux и перенаправить ее вывод в файл.
Просмотреть файл.
С помощью мыши скопировать содержимое файла в буфер обмена.
Вставить содержимое в другое приложение.

С xclip мы можем значительно сократить этот процесс:
1. Направить вывод команды Linux в xclip.
2. Вставить содержимое в другое приложение.

Управление буфером обмена из командной строки  

215

И, наоборот, можно вставить текст в файл, чтобы обработать его с помощью
команд Linux. Обычная последовательность действий:
1. Использовать мышь, чтобы скопировать текст в текущую программу.
2. Вставить его в текстовый файл.
3. Обработать текстовый файл командами Linux.
С помощью xclip -o можно обойтись без промежуточного текстового файла:
1. С помощью мыши скопировать текст в текущую программу.
2. Передать вывод xclip -o другим командам Linux для обработки.
Если вы читаете цифровую версию этой книги на устройстве c ОС Linux
и хотите попробовать некоторые команды xclip из этого раздела, не копируйте и не вставляйте команды в окно оболочки. Вводите команды
вручную. Почему? Потому что ваша операция копирования может перезаписать тот же X-буфер обмена, к которому команды обращаются с помощью xclip, что приведет к неожиданным результатам.

По умолчанию команда xclip читает стандартный ввод и записывает в первичный буфер обмена. Она может читать из файла:
$ xclip < myfile.txt

или из канала:
$ echo "Efficient Linux at the Command Line" | xclip

Теперь выведем текст в стандартный вывод или передадим выделенное содержимое другим командам, таким, например, как wc:
$ xclip -o
Efficient Linux at the Command Line
$ xclip -o > anotherfile.txt
$ xclip -o | wc -w
6

Вставка в stdout
Вставка в файл
Подсчет количества слов

Любая составная команда, записывающая данные в стандартный вывод, может
передавать свои результаты в xclip, как, например, следующая из раздела «Команда #6: uniq» на с. 30:
$ cut -f1 grades | sort | uniq -c | sort -nr | head -n1 | cut -c9 | xclip

Очистим первичный буфер обмена, поместив в него пустую строку с помощью
команды echo -n:
$ echo -n | xclip

216  Глава 10. Эффективное использование клавиатуры

Параметр -n важен, так как в противном случае echo выводит в стандартный
вывод символ новой строки, который оказывается в первичном буфере обмена.
Чтобы скопировать текст в системный буфер обмена вместо первичного, запустим xclip с параметром -selection clipboard:
$ echo https://oreilly.com | xclip -selection clipboard
$ xclip -selection clipboard -o
https://oreilly.com

Копировать
Вставить

Параметры xclip могут быть сокращены, если они недвусмысленны:
$ xclip -sel c -o То же самое, что и
https://oreilly.com

xclip -selection clipboard -o

Запустим окно браузера Firefox, чтобы посетить предыдущий URL-адрес, используя подстановку команд:
$ firefox $(xclip -selection clipboard -o)

В Linux имеется и другая команда — xsel, которая также считывает и записывает
X-буферы обмена. У нее есть несколько дополнительных функций, таких как
очистка выделения (xsel -c) и добавление к выделению (xsel -a). Изучите
справочную страницу и поэкспериментируйте с xsel.

Улучшение работы менеджера паролей
Давайте воспользуемся вашими новыми знаниями о xclip, чтобы интегрировать
X-буферы обмена в менеджер паролей pman из раздела «Создание менеджера паролей» на с. 190. Когда модифицированный сценарий pman находит соответствие
одной строке в файле vault.gpg, он записывает имя пользователя в системный
буфер обмена, а пароль — в первичный. После этого вы можете, например, заполнить любую страницу входа в интернете, вставив имя пользователя с помощью
Ctrl-V, а пароль — с помощью средней кнопки мыши.
Убедитесь, что вы не используете менеджер буфера обмена или другие
приложения, которые отслеживают X-буферы обмена и их содержимое.
В противном случае имена пользователей и/или пароли станут видны
в диспетчере буфера обмена, что представляет угрозу безопасности.

Новая версия pman приведена в листинге 10.3. Поведение pman изменилось следующим образом:

Управление буфером обмена из командной строки  

217

Новая функция load_password загружает связанные имя пользователя
и пароль в X-буферы обмена.
Если сценарий pman находит единственное совпадение либо по ключу
(поле 3), либо по любой другой части строки, он запускает load_password.
Если pman находит несколько совпадений, он печатает все ключи и примечания (поля 3 и 4) из совпадающих строк, чтобы пользователь мог
снова выполнить поиск по ключу.
Листинг 10.3. Улучшенный сценарий pman, загружающий имя пользователя
и пароль в качестве элементов буферов обмена
#!/bin/bash
PROGRAM=$(basename $0)
DATABASE=$HOME/etc/vault.gpg
load_password () {
# Помещает имя пользователя (поле 1) в системный буфер обмена
echo "$1" | cut -f1 | tr -d '\n' | xclip -selection clipboard
# Помещает пароль (поле 2) в первичный буфер обмена
echo "$1" | cut -f2 | tr -d '\n' | xclip -selection primary
# Сообщение для пользователя
echo "$PROGRAM: Found» $(echo "$1" | cut -f3- --output-delimiter ': ')
echo "$PROGRAM: username and password loaded into X selections"
}
if [ $# -ne 1 ]; then
>&2 echo "$PROGRAM: look up passwords"
>&2 echo "Usage: $PROGRAM string"
exit 1
fi
searchstring="$1"
# Сохраняет расшифрованный текст в переменной
decrypted=$(gpg -d -q "$DATABASE")
if [ $? -ne 0 ]; then
>&2 echo "$PROGRAM: could not decrypt $DATABASE"
exit 1
fi
# Ищет точные совпадения в третьем столбце
match=$(echo "$decrypted" | awk '$3~/^'$searchstring'$/')
if [ -n "$match" ]; then
load_password "$match"
exit $?
fi
# Ищет любые совпадения
match=$(echo "$decrypted" | awk "/$searchstring/")
if [ -z "$match" ]; then
>&2 echo "$PROGRAM: no matches"
exit 1
fi

218  Глава 10. Эффективное использование клавиатуры

# Подсчитывает количество совпадений
count=$(echo "$match" | wc -l)
case "$count" in
0)
>&2 echo "$PROGRAM: no matches"
exit 1
;;
1)
load_password "$match"
exit $?
;;
*)
>&2 echo "$PROGRAM: multiple matches for the following keys:"
echo "$match" | cut -f3
>&2 echo "$PROGRAM: rerun this script with one of the keys"
exit
;;
esac

Запустим сценарий:
$ pman dropbox
Passphrase: xxxxxxxx
pman: Found dropbox: dropbox.com account for work
pman: username and password loaded into X selections
$ pman account
Passphrase: xxxxxxxx
pman: multiple matches for the following keys:
google
dropbox
bank
dropbox2
pman: rerun this script with one of the keys

Пароли находятся в первичном буфере обмена, пока он не будет перезаписан.
Чтобы автоматически сбросить пароль через, например, 30 секунд, добавьте
следующую строку в функцию load_password:
(sleep 30 && echo -n | xclip -selection primary) &

Эта строка запускает подоболочку в фоновом режиме, а через 30 секунд ожидания команда очищает первичный буфер обмена, записывая в него пустую
строку. Число секунд ожидания может быть установлено на ваше усмотрение.
Если вы определили сочетание клавиш для запуска окон терминала (см. раздел
«Мгновенный запуск оболочек и браузера» на с. 201), то теперь у вас есть быстрый способ доступа к своим паролям. Откройте терминал с помощью горячей
клавиши, запустите pman и закройте терминал.

Резюме  219

Резюме
Надеюсь, что эта глава вдохновила вас на использование новых приемов, позволяющих «держать руки на клавиатуре». Сначала они могут показаться трудными,
но с практикой дойдут до автоматизма. Тогда ваши навыки станут предметом
зависти друзей и коллег, поскольку вы сможете быстро манипулировать окнами
рабочего стола, веб-контентом и буферами обмена, так, как не умеет бо`льшая
часть пользователей, привязанных к мышке.

ГЛАВА 11

Финальные советы по экономии
времени

Мне было весело и приятно писать эту книгу, и я надеюсь, что вы получили
удовольствие от ее чтения. Напоследок давайте рассмотрим несколько более мелких тем, которым не нашлось места в предыдущих главах. Эти темы
позволили мне лучше использовать возможности Linux, и, возможно, они
помогут и вам.

Способы решения задач легко и быстро
Некоторые способы экономии времени легко освоить за несколько минут.

Переход в текстовый редактор напрямую из команды less
Когда вы просматриваете текстовый файл с помощью less и хотите отредактировать его, не выходите из программы less. Просто нажмите v, чтобы запустить ваш текстовый редактор, установленный по умолчанию. Он загружает
файл и помещает курсор в место, на котором вы находились при просмотре
с помощью less. Выйдите из редактора, и вы вернетесь к стандартному выводу команды less.
Чтобы этот трюк работал лучше, установите в переменные окружения EDITOR
и/или VISUAL команду вызова вашего любимого текстового редактора. В этих
переменных окружения задается текстовый редактор Linux по умолчанию,
который можно запустить при выполнении различных команд, включая less,

Способы решения задач легко и быстро  

221

lynx, git, crontab и многочисленных программ для работы с электронной почтой.

Например, чтобы установить Emacs в качестве редактора по умолчанию, поместите одну из следующих строк (или обе) в файл конфигурации оболочки
и примените его:
VISUAL=emacs
EDITOR=emacs

Если вы сами не установите эти переменные, по умолчанию будет запускаться
редактор, предустановленный в вашей системе Linux, обычно это Vim. Если вы
оказались в Vim и не знаете, как его использовать, не паникуйте. Выйдите, нажав Escape, а затем, набрав :q!, нажмите Enter. Чтобы выйти из Emacs, нажмите
Ctrl-X, а затем Ctrl-C.

Редактирование файлов, содержащих заданную строку
Хотите отредактировать каждый файл в текущем каталоге, который содержит
определенную строку (или регулярное выражение)? Сгенерируйте список имен
файлов с помощью grep -l и передайте их вашему редактору с помощью подстановки команд. Если ваш редактор — Vim, тогда команда выглядит следующим
образом:
$ vim $(grep -l string *)

Отредактируйте все файлы, содержащие заданную строку, во всем дереве каталогов (текущем каталоге и всех подкаталогах), добавив параметр -r (рекурсивный)
в grep и начав с текущего каталога (точка):
$ vim $(grep -lr string .)

Для более быстрого поиска в разветвленных каталогах используйте find вместе
с xargs вместо grep -r:
$ vim $(find . -type f -print0 | xargs -0 grep -l string)

В разделе «Способ #3: подстановка команд» на с. 138 эта техника уже обсуждалась, но напомнить о ней еще раз было необходимо, так как она действительно
очень полезна. Не забывайте про имена файлов, содержащие пробелы и другие
специальные символы, поскольку они могут привести к неожиданным результатам, как описано в разделе «Специальные символы и подстановка команд»
на с. 139.

222  Глава 11. Финальные советы по экономии времени

Смиритесь с опечатками
Если вы постоянно ошибаетесь в написании команд, определите псевдонимы
для ваших наиболее распространенных ошибок, чтобы правильная команда все
равно выполнялась:
alias firfox=firefox
alias les=less
alias meacs=emacs

Будьте осторожны, чтобы случайно не затенить (переопределить) существующую команду Linux, определив псевдоним с тем же именем. Сначала поищите
предложенный псевдоним с помощью команд which или type (см. раздел «Расположение исполняемых программ» на с. 49) и запустите команду man, чтобы
убедиться, что нет другой команды с таким же именем:
$ type firfox
bash: type: firfox: not found
$ man firfox
No manual entry for firfox

Быстрое создание пустых файлов
В Linux существует несколько способов создания пустых файлов. Команда touch
обновляет метку времени в файле или создает файл, если он еще не существует:
$ touch newfile1

touch отлично подходит для создания большого количества пустых файлов для

тестирования:
$
$
$
$
$

mkdir tmp
cd tmp
touch file{0000..9999}.txt
cd ..
rm -rf tmp

Создать каталог
Создать 10 000 файлов
Удалить каталог и файлы

Команда echo создаст пустой файл, когда ее вывод перенаправляется в файл, но
только если будет указана опция -n:
$ echo -n > newfile2

Если вы забудете параметр -n, итоговый файл будет содержать один символ
новой строки, поэтому не будет пустым.

Способы решения задач легко и быстро  

223

Обработка файла построчно
Когда вам нужно обработать файл построчно, запустите его в цикле while read:
$ cat myfile | while read line; do
...делайте что-нибудь здесь...
done

Например, чтобы вычислить длину каждой строки файла /etc/hosts, передайте
каждую строку в wc -c:
$ cat /etc/hosts | while read line; do
echo "$line" | wc -c
done
65
31
1


Более практичный пример этого метода приведен в листинге 9.3.

Список команд, поддерживающих рекурсию
В разделе «Команда find» на с. 93 мы познакомились с командой find -exec,
которая рекурсивно применяет любую команду Linux ко всему дереву каталогов:
$ find . -exec ваша команда здесь \;

Некоторые другие команды поддерживают рекурсию, и если вы знаете о них, то
сэкономите время, используя эту возможность вместо создания команды find:
ls -R

чтобы рекурсивно перебирать каталоги и их содержимое;
cp -r или cp -a

для рекурсивного копирования каталогов и их содержимого;
rm -r

для рекурсивного удаления каталогов и их содержимого;
grep -r

для поиска по регулярному выражению в дереве каталогов;

224  Глава 11. Финальные советы по экономии времени

chmod -R

чтобы рекурсивно изменять права на доступ к файлам;
chown -R

чтобы рекурсивно изменять владельцев файлов;
chgrp -R

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

Читайте справочные страницы
Выберите часто используемую команду, например cut или grep, и внимательно
прочитайте ее справочную страницу. Наверняка вы обнаружите возможности,
которыми никогда не пользовались, и найдете их полезными. Периодически
обращайтесь к справке, чтобы оттачивать и расширять ваш инструментарий.

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

Прочтите справочную страницу команды bash
Запустите man bash, чтобы отобразить полную официальную документацию по
bash, и прочитайте ее целиком — да, более 40 тыс. слов:
$ man bash | wc -w
46318

Не торопитесь, прочтите все внимательно, даже если потребуется несколько
дней. После этого вы наверняка сможете упростить работу в Linux.

Способы решения задач, требующие затрат времени на изучение  

225

Изучите команды cron, crontab и at
В разделе «Первый пример: поиск файлов» на с. 184 есть краткое примечание о планировании автоматического запуска команд через равные промежутки времени.
Изучите программу crontab, чтобы настроить планирование команд. Например, вы
можете создавать резервные копии файлов на внешнем диске по расписанию или
отправлять себе напоминания по электронной почте о регулярных мероприятиях.
Вначале определите редактор по умолчанию (см. «Переход в текстовый редактор
напрямую из команды less» на с. 220). Запустите crontab -e, чтобы отредактировать личный файл запланированных команд. crontab запускает редактор по
умолчанию и открывает пустой файл crontab для указания команд.
Запланированная команда в файле crontab, часто называемая заданием cron,
состоит из шести полей, расположенных в одной строке. В первых пяти полях
указывается расписание задания — минуты, часы, день, месяц и день недели.
Шестое поле предназначено для команды Linux. Вы можете запускать команду
ежечасно, ежедневно, еженедельно, ежемесячно, ежегодно, в определенные дни
или время либо задавать другие, более сложные комбинации. Примеры:
*
30
30
30
30

*
7
7
7
7

*
*
5
5
*

*
*
*
1
*

*
*
*
*
1

command
command
command
command
command







Запуск
Запуск
Запуск
Запуск
Запуск

команды
команды
команды
команды
команды

каждую минуту
в 07:30 каждый
в 07:30 пятого
в 07:30 пятого
в 07:30 каждый

день
числа каждого месяца
января каждого года
понедельник

Когда вы заполнили все шесть полей, сохранили файл и вышли из редактора,
команда запускается автоматически программой cron в соответствии с заданным
расписанием. Синтаксис расписаний хорошо задокументирован на справочной
странице (man 5 crontab) и в многочисленных онлайн-учебниках (поищите
в интернете «учебник по cron» («cron tutorial»)).
Я также рекомендую изучить команду at, которая планирует одноразовое выполнение команд в указанную дату и время. За подробностями обращайтесь
к справочной странице (man at). Пример команды, которая отправит вам напоминание по электронной почте завтра в 22:00 о чистке зубов (brush your teeth):
$ at 22:00 tomorrow
warning: commands will be executed using /bin/sh
at> echo brush your teeth | mail $USER
at> ^D Нажмите Ctrl-D для завершения ввода
job 699 at Sun Nov 14 22:00:00 2021

226  Глава 11. Финальные советы по экономии времени

Чтобы получить список ожидающих выполнения заданий at, запустите atq:
$ atq
699

Sun Nov 14 22:00:00 20211 a smith

Чтобы просмотреть команды в задании at, запустите at -c с номером задания
и выведите на экран последние несколько строк:
$ at -c 699 | tail

echo brush your teeth | mail $USER

Чтобы удалить ожидающее задание до его выполнения, запустите atrm с номером задания:
$ atrm 699

Изучите команду rsync
Для копирования полного каталога, включая его подкаталоги, из одного места на
диске в другое многие пользователи Linux используют команду cp -r или cp -a:
$ cp -a dir1 dir2

cp отлично справляется с задачей в первый раз, но, если позже вы измените
несколько файлов в каталоге dir1 и снова выполните копирование, команда cp

будет не очень эффективна. Она добросовестно копирует все файлы и каталоги
из dir1 снова и снова, даже если идентичные копии уже существуют в dir2.

Команда rsync — более умная программа, которая копирует только различия
между первым и вторым каталогами:
$ rsync -a dir1/ dir2

Слеш в предыдущей команде означает копирование файлов из dir1. Без
косой черты rsync скопировала бы и сам каталог dir1, создав dir2/dir1.

Если вы позже добавите файл в каталог dir1, rsync скопирует только его. Если
вы измените одну строку внутри файла в каталоге dir1, rsync скопирует только
эту строку! Это значительно экономит время при многократном копировании
больших каталогов. Также rsync может копировать на удаленный сервер через
SSH-соединение.

Способы решения задач, требующие затрат времени на изучение  

227

rsync имеет десятки параметров. Вот некоторые особенно полезные:
-v (от verbose — подробный)

Вывод на экран имен файлов по мере их копирования.
-n

Имитация копирования. Комбинируйте с -v, чтобы увидеть, какие файлы
будут скопированы.
-x

Указывает rsync не пересекать границы файловой системы.
Я настоятельно рекомендую освоить работу с rsync для более эффективного
копирования. Прочтите справочную страницу и просмотрите примеры в статье
Rsync Examples in Linux Корбина Брауна (Korbin Brown), https://linuxconfig.org/
rsync-command-examples.

Изучите другой язык для написания сценариев
Сценарии оболочки удобны и эффективны, но имеют ряд серьезных недостатков.
Например, они плохо обрабатывают имена файлов, содержащие пробельные
символы. Рассмотрим короткий сценарий bash для удаления файла:
#!/bin/bash
BOOKTITLE="Slow Inefficient Linux"
rm $BOOKTITLE # Ошибка! Не делайте этого!

Кажется, что вторая строка указывает на файл с именем Slow Inefficient Linux,
но это не так. Сценарий будет пытаться удалить три файла с именами Slow,
Inefficient и Linux. Оболочка вычисляет переменную $BOOKTITLE перед вызовом
rm, и ее расширение состоит из трех слов, разделенных пробелами, как если бы
мы набрали следующее:
rm Slow Efficient Linux

Затем оболочка вызывает rm с тремя аргументами, что может привести к неприятностям, поскольку она попытается удалить не те файлы. В правильной команде
удаления $BOOKTITLE необходимо заключить в двойные кавычки:
rm "$BOOKTITLE"

которые оболочка расширяет до:
rm "Slow Efficient Linux"

228  Глава 11. Финальные советы по экономии времени

Такая неочевидная потенциально опасная особенность — лишь один из многих
примеров, показывающих, что сценарии оболочки непригодны для сложных
проектов. Поэтому рекомендую изучить и использовать для написания сценариев такой язык, как, например, Perl, PHP, Python или Ruby. Все они правильно
обрабатывают пробелы, поддерживают реальные структуры данных, имеют
мощные функции обработки строк и удобны для математических расчетов.
Список преимуществ можно продолжить.
Используйте оболочку для запуска сложных команд и создания простых скриптов, но в случае ответственных задач обратитесь к другому языку. Попробуйте
один из многочисленных онлайн-курсов по понравившемуся языку.

Используйте make для задач, не связанных
с программированием
Программа make автоматически обновляет файлы на основе списка правил.
Она предназначена, в первую очередь, для ускорения разработки программного
обеспечения, но, если приложить небольшие усилия, может упростить и другие
задачи.
Рассмотрите использование make при следующих условиях:
Есть группа файлов, требующих обновления.
Имеется правило, которое связывает файлы, например: book.txt требует
обновления всякий раз, когда изменяется какой-либо файл главы.
Есть команда, выполняющая обновление.
make считывает файл конфигурации, обычно называемый Makefile, в котором со-

браны правила и команды. Например, в следующем Makefile указано, что book.txt
зависит от трех файлов глав:
book.txt: chapter1.txt chapter2.txt chapter3.txt

Если целевой файл (в данном случае book.txt) старше любого из зависимых
(файлов глав), то make считает его устаревшим. Если в строке после правила
указана команда, make запускает ее для обновления целевого файла:
book.txt: chapter1.txt chapter2.txt chapter3.txt
cat chapter1.txt chapter2.txt chapter3.txt > book.txt

Чтобы применить правило, просто запустим make:

Способы решения задач, требующие затрат времени на изучение  

229

$ ls
Makefile chapter1.txt chapter2.txt chapter3.txt
$ make
cat chapter1.txt chapter2.txt chapter3.txt > book.txt Выполняется команда из
Makefile
$ ls
Makefile book.txt chapter1.txt chapter2.txt chapter3.txt
$ make
make: 'book.txt' is up to date.
$ vim chapter2.txt
Обновим файл chapter2.txt
$ make
cat chapter1.txt chapter2.txt chapter3.txt > book.txt

Команда make была разработана для программистов, но после недолгого изучения вы сможете использовать ее для задач, не связанных с программированием.
Если вам нужно обновить файлы, которые зависят от других файлов, вы сможете
упростить работу, написав Makefile.
Команда make помогла мне при написании и редактировании этой книги. Я использовал язык форматирования текста AsciiDoc и регулярно преобразовывал
главы в HTML для просмотра в браузере. Вот правило make для преобразования
файла AsciiDoc в файл HTML:
%.html: %.asciidoc
asciidoctor -o $@ $<

Оно гласит: чтобы создать файл с расширением .html (%.html), надо использовать
файл с расширением .asciidoc (%.asciidoc). Если файл HTML старше, чем файл
AsciiDoc, следует повторно создать файл HTML, запустив команду asciidoctor
для зависимого файла ($

Перейти к концу документа

/

Поиск текста вперед (введите текст и нажмите Enter)

?

Поиск текста назад (введите текст и нажмите Enter)

n

Найти следующее вхождение искомого текста

q

Выйти из man

Или другую программу, если вы переопределите значение переменной оболочки PAGER.

242  Приложение A. Памятка по Linux

Сценарии оболочки
Чтобы запустить несколько команд Linux как единое целое, выполните следующие действия:
1. Поместите команды в файл.
2. Вставьте волшебную первую строку.
3. Сделайте файл исполняемым с помощью chmod.
4. Запустите файл.
Этот файл называется сценарием (оболочки). Волшебной первой строкой должны
быть символы #! , а после них указывается путь к программе, которая считывает
и запускает сценарий1:
#!/bin/bash

Ниже приведен сценарий оболочки, который передает приветствие и печатает
сегодняшнюю дату. Строки, начинающиеся с #, являются комментариями:
#!/bin/bash
# Это просто пример скрипта
echo "Hello there!"
date

С помощью текстового редактора сохраните эти строки в файл с именем howdy.
Затем сделайте файл исполняемым с помощью одной из команд:
$ chmod 755 howdy
$ chmod +x howdy

Установите все разрешения, включая разрешение на выполнение
Просто добавьте разрешение на выполнение

и запустите его:
$ ./howdy
Hello there!
Fri Sep 10 17:00:52 EDT 2021

1

Если вы не укажете #!, то сценарий запустит ваша оболочка по умолчанию. Хорошим тоном
считается явное указание используемой оболочки.

Получение привилегий суперпользователя  

243

Начальная точка и косая черта (./) указывают на то, что сценарий находится
в вашем текущем каталоге. Без них оболочка Linux не найдет сценарий2:
$ howdy
howdy: command not found

Оболочки Linux предоставляют некоторые функции языка программирования,
полезные в сценариях. В bash, например, можно использовать операторы if,
циклы for, циклы while и другие управляющие структуры. Несколько примеров
разбросаны по всей книге. Описание синтаксиса ищите в man bash.

Получение привилегий суперпользователя
Некоторые файлы, каталоги и программы защищены от обычных пользователей,
включая вас:
$ touch /usr/local/avocado Попробуйте создать файл в системном каталоге
touch: cannot touch '/usr/local/avocado': Permission denied

Permission denied (отказано в доступе) обычно означает, что вы пытались
получить доступ к защищенным ресурсам. Они доступны только суперпользователю Linux (имя пользователя root). Большинство систем Linux
поставляются с программой sudo, которая позволяет вам стать суперпользователем на время выполнения одной команды. Если вы установили Linux
самостоятельно, ваша учетная запись, вероятно, уже настроена для запуска
sudo. Если вы являетесь пользователем в чужой системе Linux, привилегии
суперпользователя могут быть недоступны для вас — выясните это у системного администратора.
Предположим, что вы можете получить привилегии суперпользователя. Тогда
просто выполните команду sudo, указав команду для запуска от имени суперпользователя. Вам будет предложено ввести пароль для входа в систему, после
чего команда будет выполняться с привилегиями root:

2

Это связано с тем, что текущий каталог обычно не указывается в пути поиска оболочки из
соображений безопасности. В противном случае злоумышленник мог бы поместить вредоносный исполняемый сценарий, например с именем ls, в ваш текущий каталог. Тогда при
запуске ls вместо этой команды выполнился бы вредоносный сценарий.

244  Приложение A. Памятка по Linux

$ sudo touch /usr/local/avocado Создайте файл как root
[sudo] password for smith: password here
$ ls -l /usr/local/avocado Посмотрите атрибуты файла
-rw-r--r-- 1 root root 0 Sep 10 17:16 avocado
$ sudo rm /usr/local/avocado
Удалите файл как root

sudo может запомнить (кэшировать) ваш пароль на некоторое время, в зави-

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

Дополнительная литература
Чтобы узнать больше об основах использования Linux, прочитайте мою предыдущую книгу Linux Pocket Guide, которая вышла в издательстве O'Reilly, или поищите онлайн-руководства (https://ubuntu.com/tutorials/command-line-for-beginners).

ПРИЛОЖЕНИЕ Б

Если вы используете не bash

В этой книге предполагается, что вы используете оболочку bash, но если это не
так, таблица Б.1 поможет адаптировать примеры книги для других оболочек.
Символ галочки  указывает на совместимость — данная функция достаточно
похожа на bash, поэтому примеры в книге должны работать правильно. Однако
в других ситуациях поведение такой функции может отличаться от функции
bash. Внимательно прочитайте все сноски.
Независимо от используемой оболочки входа в систему, сценарии, начинающиеся с #!/bin/bash, обрабатываются bash.

Если хотите поэкспериментировать с другой оболочкой, установленной в вашей
системе, просто запустите ее, назвав по имени (например, ksh), а когда захотите
закончить, нажмите Ctrl-D. Чтобы изменить оболочку входа в систему, прочтите
man chsh.

Таблица Б.1. Функции bash, поддерживаемые другими оболочками
Функция bash
Alias

dash



fish

ksh

tcsh

zsh

, но alias 
имя не выводит псевдоним

Знак равенства 
(=) не нужен:









ksh -c

tcsh -c

zsh -c

Запуск в фоновом
режиме (&)



bash -c

dash -c fish -c

alias g
grep

246  Приложение Б. Если вы используете не bash

Функция bash
bash команда

dash

fish

ksh

tcsh

zsh

dash

fish

ksh

tcsh

zsh

/bin/ksh

/bin/tcsh

/bin/zsh

Расположение
/bin/dash /bin/fish
команды, запускающей оболочку (для
bash — /bin/
bash)
Переменная BASH_

SUBSHELL

Расширение фигурных скобок {}

Используйте seq

Формат
только вида
{a,b,c,},
а не {a..c}



Используйте



cd -











cd











Переменная



set
CDPATH



set cdpath 
= (каталог1

Используйте



Используйте об- 
ратные кавычки

Используйте







Редактирование
командной строки
с помощью клавишстрелок



1





Редактирование
командной строки
в стиле Emacs



1







Запустите



CDPATH

Подстановка команд 
с помощью $()
Подстановка команд 
с помощью обратных
кавычек

значение
()

()

Редактирование
командной строки
в стиле Vim с помощью set -o vi
complete

Другой
синтаксис2

seq

каталог2 ...)

bindkey -v

Другой синтак- Другой
сис2
синтаксис2

compdef2

Приложение Б. Если вы используете не bash  

Функция bash

Условные списки
с использованием
|| и &&

dash



fish



ksh



tcsh

zsh





Файлы конфигурации .profile
в каталоге $HOME
(см. документацию
для подробностей)

.config/fish/ .profile,
config.fish
.kshrc

.cshrc

.zprofile,
.zshrc,
.zlogin,
.zlogout

Структуры управления: for, if и т. д.

Другой
синтаксис

Другой
синтаксис





















dirs





echo



Экранирование
псевдонима с помощью \





Экранирование с по- 
мощью \









exec











Код возврата
с помощью $?



$status







export



set -x имя 
значение

setenv имя
значение



Функции

3

Другой
синтаксис




См. переменные
с именами,
начинающимися
с HIST_,
в документации

Переменная

HISTCONTROL

Переменная

HISTFILE

Переменная

HISTFILESIZE

247

set fish_
history

путь



set
histfile =



путь

set
+SAVEHIST
savehist =

значение

248  Приложение Б. Если вы используете не bash

Функция bash

dash

history

history -c

fish

ksh

tcsh

zsh

, но без
нумерации
команд

history как

псевдоним для



history
clear

Удалите

~/.sh_
history
и перезапустите ksh

history -p

hist -l

Расширение истории
с помощью ! и ^





Пошаговый поиск по
истории с помощью

Введите начало 1, 4
команды,
затем нажмите
стрелку вверх
для поиска,
стрелку вправо
для выбора

5

6

history число

history
-число

history
-N число



history
-число

Перемещение по
истории команд
с помощью клавишстрелок



1





Перемещение по
истории команд
в стиле Emacs



1





Перемещение по
истории команд
в стиле Vim с помощью set -o vi



Запустите



Переменная



Ctrl-R

HISTSIZE

Управление задани- 
ями с помощью fg,
bg, Ctrl-Z, jobs





bindkey -v


7



Приложение Б. Если вы используете не bash  

Функция bash

dash

fish

ksh

tcsh

zsh

Сопоставление с ша- 
блоном с помощью
*, ?, []









Каналы















popd



Подстановка процесса с помощью )







Перенаправление
stdin (, >>)











Добавьте



Добавьте

>&



source или .

Только
точка9



9

Подоболочки с помощью ()



Перенаправление
stdout + stderr (&>)
(точка)

2>&18

Завершение имен
файлов и каталогов
с помощью табуляции
type



2>&18



9









1







type — это

which



псевдоним для

whence -v

249

250  Приложение Б. Если вы используете не bash

Функция bash

dash

fish

ksh

tcsh

zsh

unalias



functions
--erase







Определение
переменной с помощью записи
имя=значение



set имя



set имя =



Вычисление переменной с помощью











значение

значение

$name
1

Эта функция отключена по умолчанию. Запустите set -o emacs, чтобы включить ее.
Старые версии ksh могут вести себя иначе.

2

Пользовательское завершение команды с использованием команды complete или аналогичной значительно отличается в разных оболочках. См. документацию к конкретной
оболочке.

3

Не поддерживается стиль определения функций, в котором они начинаются с ключевого
слова function.

4

Пошаговый поиск по истории команд работает в ksh иначе. Нажмите Ctrl-R, введите
строку и нажмите Enter, чтобы вызвать самую последнюю команду, содержащую эту
строку. Нажмите Ctrl-R и Enter еще раз, чтобы найти следующую совпадающую команду
в обратном направлении и т. д. Нажмите Enter, чтобы выполнить ее.

5

Чтобы включить пошаговый поиск в истории команд с помощью Ctrl-R в tcsh, выполните команду bindkey ^R i-search-back (и добавьте ее в файл конфигурации оболочки).
Поведение немного отличается от bash. Cм. man tcsh.

6

7

В режиме vi введите /, а затем строку поиска, затем нажмите Enter. Нажмите n, чтобы
перейти к следующему результату поиска.
tcsh не отслеживает номер задания по умолчанию так удобно, как другие оболочки,

поэтому вам может потребоваться указать номер задания, например %1, в качестве
аргумента для fg и bg.
8

Синтаксис в этой оболочке следующий: команда > file 2>&1. Последнее выражение
2>&1 означает «перенаправить stderr, который является дескриптором файла 2, на stdout,
который является дескриптором файла 1».

9

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

Об авторе

Дэниел Джей Барретт преподает Linux и родственные технологии и пишет
о них уже более 30 лет. Автор множества книг издательства O'Reilly, таких как
Linux Pocket Guide, Linux Security Cookbook, SSH, The Secure Shell: The Definitive
Guide, Macintosh Terminal Pocket Guide и MediaWiki. Помимо этого Дэн в разное
время был разработчиком программного обеспечения, рок-певцом, системным
администратором, преподавателем в университете, веб-дизайнером и стендапером. Работает в Google. Более подробную информацию ищите по адресу
https://danieljbarrett.com/.

Иллюстрация на обложке

На обложке книги изображен балобан (Falco cherrug).
Быстрые, мощные и агрессивные, эти пернатые хищники ценятся любителями
соколиной охоты на протяжении тысячелетий. Сегодня они являются национальной птицей нескольких стран, например Венгрии, Монголии и Объединенных
Арабских Эмиратов.
Длина тела взрослых балобанов часто превышает 50 см, при этом размах крыльев составляет 97–126 см. Самки этого вида значительно крупнее самцов, их
вес — 970–1300 г против 730–990 г у последних. Цвет оперения у птиц сильно
различается: от темно- до бледно-коричневого или даже белого с коричневыми
полосами.
В дикой природе балобаны охотятся в основном на птиц и грызунов, развивая
скорость полета до 120–150 км/ч, прежде чем наброситься на добычу. Типичные
места обитания включают луга, скалистые районы и галерейные леса, где соколы
занимают гнезда, покинутые другими птицами. За исключением самых южных
ареалов обитания, балобаны являются перелетными птицами, они ежегодно отправляются на зимовку из Восточной Европы и Центральной Азии в северные
части Африки и Южной Азии.
У балобанов нет врагов в дикой природе. Тем не менее их популяция сокращается и балобан считается видом, находящимся под угрозой исчезновения, как
и многие другие животные на обложках книг издательства O'Reilly. Все они
важны для нашего мира.
Иллюстрацию для обложки выполнила Карен Монтгомери (Karen Montgomery)
на основе старинной гравюры из книги 1894 г. Ричарда Лидеккера (Richard
Lydekker) The Royal Natural History.

Дэниел Джей Барретт
Linux. Командная строка. Лучшие практики
Перевел с английского А. Гаврилов

Руководитель дивизиона
Руководитель проекта
Ведущий редактор
Литературный редактор
Художественный редактор
Корректоры
Верстка

Ю. Сергиенко
А. Питиримов
Е. Строганова
Д. Гудилин
В. Мостипан
Л. Галаганова, М. Молчанова
Е. Цыцен

Изготовлено в России. Изготовитель: ООО «Прогресс книга».
Место нахождения и фактический адрес: 194044, Россия, г. Санкт-Петербург,
Б. Сампсониевский пр., д. 29А, пом. 52. Тел.: +78127037373.
Дата изготовления: 06.2023. Наименование: книжная продукция.
Срок годности: не ограничен.
Налоговая льгота — общероссийский классификатор продукции
ОК 034-2014, 58.11.12 — Книги печатные
профессиональные, технические и научные.
Импортер в Беларусь: ООО «ПИТЕР М», 220020, РБ, г. Минск, ул. Тимирязева, д. 121/3, к. 214, тел./факс: 208 80 01.
Подписано в печать 06.04.23. Формат 70×100/16. Бумага офсетная. Усл. п. л. 20,640. Тираж 1000. Заказ 0000.

ИЗДАТЕЛЬСКИЙ ДОМ «ПИТЕР»
предлагает профессиональную, популярную
и детскую развивающую литературу
Заказать книги оптом можно в наших представительствах
РОССИЯ
Санкт-Петербург
м. «Выборгская», Б. Сампсониевский пр., д. 29а;
тел. (812) 703-73-73, доб. 6282; e-mail: dudina@piter.com
Москва
м. «Электрозаводская», Семеновская наб., д. 2/1, стр. 1, 6 этаж;
тел./факс (495) 234-38-15; e-mail: reception@piter.com
БЕЛАРУСЬ
Минск
ул. Харьковская, д. 90, пом. 18
тел./факс: +37 (517)348-60-01, 374-43-25, 272-76-56
e-mail: dudik@piter.com

Издательский дом «Питер» приглашает к сотрудничеству авторов:
тел./факс (812) 703-73-72, (495) 234-38-15; e-mail: ivanovaa@piter.com
Подробная информация здесь: http://www.piter.com/page/avtoru

Издательский дом «Питер» приглашает к сотрудничеству зарубежных
торговых партнеров или посредников, имеющих выход на зарубежный
рынок: тел./факс (812) 703-73-73, доб. 6282; e-mail: sales@piter.com
Заказ книг для вузов и библиотек:
тел./факс (812) 703-73-73, доб. 6243; e-mail: uchebnik@piter.com
Заказ книг в интернет-магазине: на сайте www.piter.com;
тел. (812) 703-73-74, доб. 6216; e-mail: books@piter.com
Вопросы по продаже электронных книг: тел. (812) 703-73-74, доб. 6217;
e-mail: кuznetsov@piter.com

ВАША УНИКАЛЬНАЯ КНИГА
Хотите издать свою книгу?
Книга может стать идеальным подарком для партнеров и друзей или
отличным инструментом продвижения личного бренда. Мы поможем
осуществить любые, даже самые смелые и сложные, идеи ипроекты!
МЫ ПРЕДЛАГАЕМ
издание вашей книги
издание корпоративной библиотеки
издание книги в качестве корпоративного подарка
издание электронной книги (формат ePub или PDF)
размещение рекламы в книгах
ПОЧЕМУ НАДО ВЫБРАТЬ ИМЕННО НАС
Более 30 лет издательство «Питер» выпускает полезные и интересные
книги. Наш опыт — гарантия высокого качества. Мы печатаем книги,
которыми могли бы гордиться и мы, и наши авторы.
ВЫ ПОЛУЧИТЕ
услуги по обработке и доработке вашего текста
современный дизайн от профессионалов
высокий уровень полиграфического исполнения
продажи книги в крупнейших книжных магазинах страны
продвижение книги (реклама в профильных изданиях и местах
продаж; рецензии в ведущих СМИ; интернет-продвижение)
Мы имеем собственную сеть дистрибуции по всей России
и в Белоруссии, сотрудничаем с крупнейшими книжными магазинами
страны и ближнего зарубежья. Издательство «Питер» — постоянный
участник многих конференций и семинаров, которые предоставляют
широкие возможности реализации книг. Мы обязательно проследим,
чтобы ваша книга имелась в наличии в магазинах и была выложена
на самых видных местах. А также разработаем индивидуальную
программу продвижения книги с учетом ее тематики, особенностей
и личных пожеланий автора.
Свяжитесь с нами прямо сейчас:
Санкт-Петербург — Анна Титова, (812) 703-73-73, titova@piter.com

ЗАКАЗ И ДОСТАВКА КНИГ
ЗАКАЗАТЬ КНИГИ ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР»
МОЖНО ЛЮБЫМ УДОБНЫМ ДЛЯ ВАС СПОСОБОМ
на нашем сайте: www.piter.com
по электронной почте: books@piter.com
по телефону: (812) 703-73-74 или 8(800) 500-42-17
ВЫ МОЖЕТЕ ВЫБРАТЬ ЛЮБОЙ УДОБНЫЙ ДЛЯ ВАС
СПОСОБ ОПЛАТЫ
Наложенным платежом с оплатой при получении в ближайшем
почтовом отделении, пункте выдачи заказов (ПВЗ) или курьеру.
С помощью банковской карты. Во время заказа вы будете
перенаправлены на защищенный сервер нашего оператора,
где сможете ввести свои данные для оплаты.
Электронными деньгами. Мы принимаем к оплате Яндекс.Деньги,
WebMoney и Qiwi-кошелек.
В любом банке, распечатав квитанцию, которая формируется
автоматически после оформления вами заказа.
ВЫ МОЖЕТЕ ВЫБРАТЬ ЛЮБОЙ УДОБНЫЙ ДЛЯ ВАС
СПОСОБ ДОСТАВКИ
курьерская доставка до дома или офиса
на пункт выдачи заказов выбранной вами транспортной
компании
в отделение «Почты России»
ПРИ ОФОРМЛЕНИИ ЗАКАЗА УКАЖИТЕ
фамилию, имя, отчество, телефон, e-mail
почтовый индекс, регион, район, населенный пункт, улицу,
дом, корпус, квартиру
название книги, автора, количество заказываемых
экземпляров