Перенаправление ввода-вывода
Всё в Linux — это файлы, в том числе — ввод и вывод. Операционная система идентифицирует файлы с использованием дескрипторов. Каждому процессу позволено иметь до девяти открытых дескрипторов файлов. Оболочка bash резервирует первые три дескриптора с идентификаторами 0, 1 и 2. Вот что они означают.
- 0, STDIN — стандартный поток ввода
- 1, STDOUT — стандартный поток вывода
- 2, STDERR — стандартный поток ошибок
STDIN
STDIN — это стандартный поток ввода оболочки. Для терминала стандартный ввод — это клавиатура. Когда используется символ перенаправления ввода — <, Linux заменяет дескриптор файла стандартного ввода на тот, который указан в команде. Система читает файл и обрабатывает данные так, будто они введены с клавиатуры.
Многие команды bash принимают ввод из STDIN, если в командной строке не указан файл, из которого надо брать данные. Например, это справедливо для команды cat.
Когда вы вводите команду cat в командной строке, не задавая параметров, она принимает ввод из STDIN. После того, как вы вводите очередную строку, cat просто выводит её на экран. И останавливается после того как получает EOF. EOF вводится нажатием сочетания клавиш Ctrl+D.
STDOUT
STDOUT — стандартный поток вывода оболочки. По умолчанию это — экран. Большинство bash-команд выводят данные в STDOUT, что приводит к их появлению в консоли. Данные можно перенаправить в файл, для этого используется символ перенаправления вывода >.
Можно осуществить перенаправление вывода в файл с добавлением в конец с помощью >>. При этом информация, хранящаяся в файле не будет удалена, а вся новая информация будет добавлена в конец этого файла.
STDERR
STDERR представляет собой стандартный поток ошибок оболочки. По умолчанию этот дескриптор указывает на то же самое, на что указывает STDOUT, именно поэтому при возникновении ошибки мы видим сообщение на экране.
Рассмотрим простой пример — нужно записать в файл data.txt содержимое директории data. Если директория не существует, сообщение об ошибке надо записать в файл error.txt. Чтобы этого добиться, нужно использовать команды перенаправления для соответствующих дескрипторов с указанием файлов, куда должны попадать ошибки и стандартный вывод:
$ ls data 1> data.txt 2> error.txt
Если надо, STDERR и STDOUT можно перенаправить в один и тот же файл, воспользовавшись &>:
$ ls data &> data-error.txt
Устаревшая форма записи:
$ ls data > data-error.txt 2>&1
Оболочка определяет порядок перенаправления потоков в командной строке слева направо, поэтому приведенный выше пример нельзя записать так:
$ ls data 2>&1 > data-error.txt
В этом случае сначала вывод ошибок перенаправляется в стандартный вывод (на экран), а потом стандартный вывод перенаправляется в файл data-error.txt. То есть, ошибки будут выведены в консоль, а данные — в файл.
Для дозаписи в файл data-error.txt
$ ls data &>> data-error.txt
Перенаправление вывода в скриптах
Существует два метода перенаправления вывода в сценариях командной строки:
- Временное перенаправление, или перенаправление вывода одной строки
- Постоянное перенаправление, или перенаправление всего вывода сценария
Временное перенаправление вывода
В сценарии можно перенаправить вывод отдельной строки в STDERR. Чтобы это сделать, достаточно использовать команду перенаправления, указав дескриптор STDERR, при этом перед номером дескриптора надо поставить символ амперсанда:
#!/bin/bash echo "This is an error" >&2 echo "This is normal output"
Если запустить этот скрипт, обе строки попадут на экран, так как, как вы уже знаете, по умолчанию ошибки выводятся туда же, куда и обычные данные.
$ ./test.sh This is an error This is normal output
Запустим скрипт так, чтобы вывод STDERR попадал в файл:
$ ./test.sh 2> error.txt This is normal output $ cat error.txt This is an error
Теперь обычный вывод делается в консоль, а сообщения об ошибках попадают в файл error.txt.
Постоянное перенаправление вывода
Если в скрипте нужно перенаправлять много выводимых на экран данных, добавлять >&2 к каждому вызову echo неудобно. Вместо этого можно задать перенаправление вывода в определённый дескриптор на время выполнения скрипта, воспользовавшись командой exec:
#!/bin/bash exec 1> output.txt echo "Это пример перенаправления всего" echo "вывода сценария в файл output.txt" echo "без перенаправления каждой строки"
После запуска сценария весь вывод будет перенаправлен в файл output.txt.
Команду exec можно использовать не только в начале скрипта, но и в других местах:
#!/bin/bash # ошибки перенаправляем в файл error.txt exec 2> error.txt # строка будет выведена на экран echo "Первый вывод сценария" # перенаправляем вывод в файл output.txt exec 1> output.txt # строка будет записана в файл output.txt echo "Второй вывод сценария" # строка будет записана в файл error.txt echo "Третий вывод сценария" >&2
Перенаправление ввода в скриптах
Для перенаправления ввода можно воспользоваться тем же способом, который использовался для перенаправления вывода. Например, команда exec позволяет сделать источником данных для STDIN какой-нибудь файл:
$ exec 0< data.txt
Эта команда указывает оболочке на то, что источником вводимых данных должен стать файл data.txt, а не обычный STDIN. Посмотрим на перенаправление ввода в действии:
#!/bin/bash exec 0< data.txt count=1 while read line ; do echo "Line #$count: $line" count=$(( $count + 1 )) done
Подавление вывода
Иногда надо сделать так, чтобы команды в скрипте, который, например, может исполняться как фоновый процесс, ничего не выводили на экран. Для этого можно перенаправить вывод в /dev/null.
Вот, например, как подавить вывод сообщений об ошибках:
$ ls -al badfile.txt file.txt 2> /dev/null
Тот же подход используется, если, например, надо очистить файл, не удаляя его:
$ cat /dev/null > data.txt