Конвейеры и перенаправление ввода-вывода в Linux

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

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

Эту статью нужно читать внимательно! Даже если механизм работы всех команд для вас очевиден, для эффективного использования важно понимать все тонкости.

Что такое конвейеры и перенаправления

К каждой программе, запускаемой в командной строке, по умолчанию подключено три потока данных: 

  • STDIN (0) — стандартный поток ввода (данные, загружаемые в программу).
  • STDOUT (1) — стандартный поток вывода (данные, которые выводит программа). По умолчанию — терминал.
  • STDERR (2) — стандартный поток вывода диагностических и отладочных сообщений (например, сообщениях об ошибках). По умолчанию — терминал.

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

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

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

Обычно мы выводим информацию в консоль, что довольно удобно. Но иногда нужно записать ее в файл, отправить на другой компьютер или другому человеку. Оператор > (больше) указывает командной строке на то, что мы хотим записать информацию в файл, а не выводить в консоль. Рассмотрим пример:

1. user@bash: ls
2. barry.txt bob example.png firstfile foo1 video.mpeg
3. user@bash: ls > myoutput
4. user@bash: ls
5. barry.txt bob example.png firstfile foo1 myoutput video.mpeg
6. user@bash: cat myoutput
7. barry.txt
8. bob
9. example.png
10. firstfile
11. foo1
12. myoutput
13. video.mpeg
14. user@bash:

Давайте разберемся, что происходит:

  • 1 строка. Проверяем, что находится в текущей директории.
  • 3 строка. Запускаем ту же команду, но в этот раз мы используем >, чтобы указать терминалу, что мы хотим записать вывод в файл myoutput. Как вы можете заметить, мы можем не создавать файл перед записью в него — терминал сделает это автоматически.
  • 4 строка. Файл действительно сам создался. 
  • 6 строка. Смотрим, что внатри файла. 

Несколько наблюдений

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

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

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

Сохранение в уже существующий файл

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

1. user@bash: cat myoutput
2. barry.txt
3. bob
4. example.png
5. firstfile
6. foo1
7. myoutput
8. video.mpeg
9. user@bash: wc -l barry.txt > myoutput
10. user@bash: cat myoutput
11. 7 barry.txt
12. user@bash:

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

1. user@bash: cat myoutput
2. 7 barry.txt
3. user@bash: ls >> myoutput
4. user@bash: cat myoutput
5. 7 barry.txt
6. barry.txt
7. bob
8. example.png
9. firstfile
10. foo1
11. myoutput
12. video.mpeg
13. user@bash:

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

Оператор < (меньше чем) — еще один способ отправки данных. Происходит это так: мы считываем содержимое файла и отправляем его с помощью потока STDIN.

1. user@bash: wc -l myoutput
2. 8 myoutput
3. user@bash: wc -l < myoutput
4. 8
5. user@bash:

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

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

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

Также мы можем легко объединять две формы перенаправления, с которыми мы уже познакомились, в одну. Например, вот так:

1. user@bash: wc -l < barry.txt > myoutput
2. user@bash: cat myoutput
3. 7
4. user@bash:

Перенаправление STDERR

Давайте теперь повнимательнее рассмотрим третий поток — STDERR. У каждого потока есть уникальный номер — они указаны в начале статьи на схеме. Эти номера можно использовать для идентификации потоков.

Если мы введем номер перед оператором >, то произойдет перенаправление на соответствующий поток. По умолчанию номер потока — 1. Номер потока STDERR — 2, давайте перенаправим на него.  

1. user@bash: ls -l video.mpg blah.foo
2. ls: cannot access blah.foo: No such file or directory
3. -rwxr--r-- 1 karpaff users 6 May 16 09:14 video.mpg
4. user@bash: ls -l video.mpg blah.foo 2> errors.txt
5. -rwxr--r-- 1 karpaff users 6 May 16 09:14 video.mpg
6. user@bash: cat errors.txt
7. ls: cannot access blah.foo: No such file or directory
8. user@bash:

Теперь представьте, что нам нужно помимо стандартного вывода сохранить в файл еще и сообщения об ошибках? Сделать это можно перенаправив поток STDERR в STDOUT, а STDOUT — в файл. Сначала мы используем перенаправление в файл, а затем перенаправляем поток STDERR. Определить перенаправление в поток можно с помощью & перед номером потока. По умолчанию номер потока — 1. 

1. user@bash: ls -l video.mpg blah.foo > myoutput 2>&1
2. user@bash: cat myoutput
3. ls: cannot access blah.foo: No such file or directory
4. -rwxr--r-- 1 karpaff users 6 May 16 09:14 video.mpg
5. user@bash:

Конвейеризация

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

Для конвейеризации существует специальный оператор — | (вертикальная черта). Вот как он рабоатет: вывод из программы слева от оператора передается в качестве ввода в программу справа от оператора. В примере ниже мы выводим только первые три файла директории с помощью оператора конвейеризации.

1. user@bash: ls
2. barry.txt bob example.png firstfile foo1 myoutput video.mpeg
3. user@bash: ls | head -3
4. barry.txt
5. bob
6. example.png
7. user@bash:

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

1. user@bash: ls | head -3 | tail -1
2. example.png
3. user@bash: 

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

Конаейеризация + перенаправление 

Конвейеризацию и перенаправление можно объединить:

1. user@bash: ls | head -3 | tail -1 > myoutput
2. user@bash: cat myoutput
3. example.png
4. user@bash: 

Совет. Лучший способ избежать ошибок при работе с конвейеризацией — писать команды постепенно. Сначала проверьте вывод первой программы и убедитесь, что всё работает правильно. И только после этого добавляйте вторую, третью и т. д. программу. Так вы сэкономите кучу времени. 

Еще несколько примеров

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

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

Пример 1. Сортируем директорию так, чтобы папки вывелись в консоль первыми

1. user@bash: ls -l /etc | tail -n +2 | sort
2. drwxrwxr-x 3 nagios nagcmd 4096 Mar 29 08:52 nagios
3. drwxr-x--- 2 news news 4096 Jan 27 02:22 news
4. drwxr-x--- 2 root mysql 4096 Mar 6 22:39 mysql
5. ...
6. user@bash: 

Пример 2. Выводим все файлы, у которых есть разрешение на запись

1. user@bash: ls -l ~ | grep '^.....w'
2. drwxrwxr-x 3 karpaff users 4096 Jan 21 04:12 dropbox
3. user@bash:

Пример 3. Выводим список пользователей, у которых есть доступ к файлам в выбранном каталоге

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

1. user@bash: ls -l /projects/ghosttrail | tail -n +2 | sed 's/\s\s*/ /g' | cut -d ' ' -f 3 | sort | uniq -c
2. 8 anne
3. 34 harry
4. 37 tina
5. 18 ryan
6. user@bash: 
codechick

СodeСhick.io - простой и эффективный способ изучения программирования.

2024 ©