Урок 8. Объединение команд - последовательное и параллельное выполнение в bash

Символы групповых операций

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

Поэтому в Linux имеются специальные символы, которые позволяют проводить данные операции над несколькими файлами.

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

Отображение файлов с одинаковым расширением в папке
Рис. 1. Отображение файлов с одинаковым расширением в папке

Необходимо скопировать  файлы image в каталог photo/. Для этого достаточно выполнить cp image* photo/.

Символ * в данном случае означает любые символы после слова image, то есть image1.jpg, image2.jpg и так далее, включая image1.txt, image2.txt и image.pdf.

Рассмотрим возможные применения данного символа в таблице:

Команда 

Результат

cp image* photo/

Все файлы image1.jpg - image15.jpg, image1.txt, image2.txt image.pdf

cp image*.jpg photo/

Только файлы image1.jpg - image15.jpg

cp *.jpg photo/

Все файлы jpg: image1.jpg - image15.jpg

cp * photo/

Абсолютно все файлы в текущем каталоге


Символ ? указывает на любой одиночный символ. Например, команда cp image?.jpg photo/ скопирует файлы image1.jpg - image9.jpg, то есть между  image и .jpg рассматривается только один знак.

Рассмотрим возможные применения данного символа:

Команда

Результат

cp image?.jpg photo/

Только image1.jpg - image9.jpg

cp image1?.jpg photo/

Только image10.jpg - image15.jpg

cp image? photo/

В нашем случае выдаст ошибку, так такого файла или каталога не существует

cp image?.* photo/

image1.jpg - image9.jpg, image1.txt и image2.txt


Квадратные скобки [] с соответствующими символами означает диапазон символов, указанных в скобках. Например, [12] означает, что в условии должен совпасть один из символов, указанных в скобках. Либо можно задать целый диапазон значений - [1-5], то есть любой символ из указанного диапазона.

Поясню на примерах:

Команда

Результат

cp image[12].jpg photo/

Только файлы image1.jpg и image2.jpg

cp image1[1-5].jpg photo/

Только файлы image11.jpg - image15.jpg

cp image[12]* photo/

image1.jpg, image2.jpg, image1.txt, image2.txt

cp image?[13].jpg photo/

Только файлы image11.jpg - image13.jpg

 

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

Объединение команд
Последовательное безусловное выполнение

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

Например, создадим каталог, скопируем группу файлов student*.jpg в данный каталог и просмотрим размер данного каталога в килобайтах. То есть мы выполним:

mkdir photo

cp student*.jpg photo/

ls -lh 

Пришлось последовательно вводить команду, затем ждать ее завершения и вводить следующую. Однако данный процесс можно оптимизировать, введя все команды одну за другой, отделив каждую точкой с запятой: mkdir photo; cp student*.jpg photo/; ls -lh.

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

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

 

Последовательное выполнение при соблюдении условия

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

Например, из каталога photo/ скопируем файлы на внешний носитель, а затем их удалим из каталога photo/: cp student*.jpg /media/StudentFlash; rm student*.jpg.

Если мы забудем подключить флэшку и выполним вышеуказанную команду, то потеряем все файлы student*.jpg, так как несмотря на ошибку система все равно выполнит вторую команду.

Чтобы избежать подобных ситуаций можно воспользоваться конструкцией cp student*.jpg /media/StudentFlash && rm student*.jpg.

То есть вместо ; мы используем &&. Проще говоря, если первая команда завершилась с ошибкой (неважно какая), то система не выполнит вторую команду. Если первая команда завершилась успешно, то будет выполнена вторая команда.

Следующий символ объединения || используется, когда из 2-х (или более) команд нужно выполнить либо первую либо вторую команду. То есть, если первая команда завершилась с ошибкой, то ход переходит следующей команде, а если первая команда все же успешно завершилась, то вторая команда выполняться не будет.

Например, перейдем в каталог music/, если его не существует то создадим его: cd music/ || mkdir music.

В нашем случае каталог music/ не существует и система выдала ошибку, поэтому будет выполнена команда mkdir music.

Передача выхода одной команды на вход другой команды

Иногда при работе с командой ls выводится слишком много информации, которая не помещается на всем экране и приходится прокручивать текст, чтобы увидеть начало:

Вывод команды слишком большой, чтобы поместиться во весь экран
Рис. 2. Вывод команды слишком большой, чтобы поместиться во весь экран

Чтобы постранично просматривать результат выполнения команд можно перенаправить вывод команды ls на вход команды less. Как мы уже знаем она используется для постраничного просмотра текстовых файлов. Для этого воспользуемся символом |: ls  | less:

Постраничный вывод результата команды
Рис. 3. Постраничный вывод результата команды

Теперь попробуем в системе найти файл под названием icon с помощью команды locate (рассмотрим подробнее позже): locate * icon.

Система может выдать сотни и тысячи значений. Здесь тоже можем воспользоваться символом |: locate * icon | less.

Разумеется все это частные случаи. В процессе изучения новых команд и работе в Linux вам придется не раз встречаться с ситуациями, когда будет необходимо воспользоваться символом |.

А можно результат команды locate записать в файл и уже потом просмотреть его содержимое командой less?

Конечно можно. Для этого существует другой символ объединения команд >: locate * icon > search_result.txt. В данном случае символом > мы записываем результат выполнения команды locate в файл search_result.txt.

А файл search_result.txt нужно предварительно создавать?

Нет, если его нет, то система создаст его автоматически. А если он есть, то система перезапишет все его содержимое.

То есть мы можем все потерять по неосторожности?

Совершенно верно, но есть 2 способа избежать этого.

1-й способ. Можно установить специальную опцию noclobber: set  -o noclobber. Теперь, если файл существует, то система выдаст следующее сообщение:

Предупреждение, что файл уже существует
Рис. 4. Предупреждение, что файл уже существует

Чтобы отключить эту опцию выполните set  +o noclobber.

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

Подстановка вывода одной команды под аргумент второй команды

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

Вместо аргументов в некоторых случаях можно использовать и результаты выполнения некоторых команд. Например, у нас имеется текстовый файл links.txt, где хранится следующая запись:

Отображение содержимого файла
Рис. 5. В текстовом файле хранится ссылка на другой файл. Данную ссылку можно подставить в другую команду в качестве аргумента

Это простая текстовая строка. Попробуем подставить данную строку, чтобы создать каталоги согласно указанной строке. Для этого можно воспользоваться конструкцией типа $(): mkdir $(cat links.txt).

Вывод команды cat был подставлен под аргумент команды mkdir.

Другой пример: mkdir $(date “+%d.%m”) создает каталог по текущей дате.