Если вы знакомы с основными командами Linux, вам также следует изучить концепцию перенаправления ввода-вывода.
Вы уже знаете, как работает команда в Linux. Она принимает вход и дает вам выход. Здесь есть несколько игроков. Позвольте нам рассказать вам о них.
Stdin, stdout и stderr
Когда вы запускаете команду Linux, в ней играют роль три потока данных:
- Стандартный ввод ( stdin ) является источником входных данных. По умолчанию стандартный ввод – это любой текст, введенный с клавиатуры. Идентификатор потока равен 0.
- Стандартный вывод ( stdout ) является результатом команды. По умолчанию он отображается на экране. Идентификатор потока равен 1.
- Стандартная ошибка ( stderr ) – это сообщение об ошибке (если есть), генерируемое командами. По умолчанию stderr также отображается на экране. Идентификатор потока равен 2.
Эти потоки содержат данные в виде простого текста в том, что называется буферной памятью.
Думайте об этом как о струе воды. Вам нужен источник для воды, например, кран. Вы подключаете к нему трубу и можете хранить ее в ведре (файле) или поливать растения (распечатывать). Вы также можете подключить его к другому крану, если это необходимо. По сути, вы перенаправляете воду.
В Linux также существует такая концепция перенаправления, при которой вы можете перенаправить stdin, stdout и stderr из обычного места назначения в другой файл или команду (или даже на периферийные устройства, такие как принтеры).
Позвольте нам показать, как работает перенаправление и как вы можете его использовать.
Перенаправление вывода
Первой и самой простой формой перенаправления является перенаправление вывода, также называемое перенаправлением stdout.
Вы уже знаете, что по умолчанию вывод команды отображается на экране. Например, мы используем команду ls для вывода списка всех файлов, и это вывод, который мы получаем:
andreyex@destroyer:~$ ls appstxt new.txt static-ip.txt
С перенаправлением вывода вы можете перенаправить вывод в файл. Если эти выходные файлы не существуют, оболочка создаст их.
command > file
Например, позвольте нам сохранить вывод команды ls в файл с именем output.txt:
andreyex@destroyer:~$ ls > output.txt
Выходной файл создается заранее
Как вы думаете, каким должно быть содержимое этого выходного файла? Позвольте нам использовать команду cat, чтобы показать вам сюрприз:
andreyex@destroyer:~$ cat output.txt appstxt new.txt output.txt static-ip.txt
Вы заметили, что включение output.txt существует ? Мы сознательно выбрали этот пример, чтобы показать вам это.
Выходной файл, на который перенаправляется стандартный вывод, создается до запуска намеченной команды. Почему? Потому что он должен иметь готовый выходной пункт назначения, на который будут отправлены выходные данные.
Добавить вместо удаления
Одна из часто игнорируемых проблем заключается в том, что если вы перенаправляете файл, который уже существует, оболочка сначала удалит ( замкнет ) файл. Это означает, что существующее содержимое выходного файла будет удалено и заменено выводом команды.
Вы можете добавить вместо перезаписи, используя >> синтаксис перенаправления.
command >> file
Зачем вам перенаправлять стандартный вывод? Вы можете сохранить выходные данные для дальнейшего использования и проанализировать их позже. Это особенно полезно, когда вывод команды слишком велик и занимает весь экран. Это как собирать бревна.
Перенаправление канала
Прежде чем вы увидите перенаправление stdin, вы должны узнать о перенаправлении канала. Это более распространено, и, вероятно, вы будете часто его использовать.
При перенаправлении канала стандартный вывод команды отправляется на стандартный ввод другой команды.
command 1 | command 2
Позвольте нам показать вам практический пример. Скажем, вы хотите посчитать количество видимых файлов в текущем каталоге. Вы можете использовать ls -1 (это цифра один, а не буква L) для отображения файлов в текущем каталоге:
andreyex@destroyer:~$ ls -1 appstxt new.txt output.txt static-ip.txt
Вы, наверное, уже знаете, что команда wc используется для подсчета количества строк в файле . Если вы объедините обе эти команды с конвейером, вот что вы получите:
andreyex@destroyer:~$ ls -1 | wc -l 4
При использовании pipe обе команды совместно используют один и тот же буфер памяти. Вывод первой команды сохраняется в буфере, и этот же буфер затем используется в качестве ввода для следующей команды.
Вы увидите результат последней команды в конвейере. Это очевидно, потому что вывод предыдущей команды (команд) подается на следующую команду (команды) вместо перехода на экран.
Перенаправление трубы или трубопровод не ограничиваются соединением только двух команд. Вы можете подключить больше команд, если выходные данные одной команды могут использоваться как входные данные следующей команды.
command_1 | command_2 | command_3 | command_4
Помните, что stdout/stdin это кусок данных, а не имена файлов
Некоторые новые пользователи Linux путаются при использовании перенаправления. Если команда возвращает набор имен файлов в качестве выходных данных, вы не можете использовать эти имена файлов в качестве аргумента.
Например, если вы используете команду find, чтобы найти все файлы, оканчивающиеся на .txt, вы не можете передать ее через канал для перемещения найденных файлов в новый каталог, а не так:
find . -type f -name "*.txt" | mv destination_directory
Вот почему вы часто будете видеть команду find, используемую в сопряжении с командой exec или xargs. Эти специальные команды «преобразуют текст с кучей имен файлов в имя файла», которые могут быть переданы в качестве аргумента.
find . -type f -name "*.txt" | xargs -t -I{} mv {} ../new_dir
Перенаправление ввода
Вы можете использовать перенаправление stdin для передачи содержимого текстового файла команде, подобной этой:
command < file
Вы не увидите, что stdin часто используется. Это потому, что большинство команд Linux принимают имена файлов в качестве аргумента и, следовательно, перенаправление stdin часто не требуется.
Возьмите это к примеру:
head < filename.txt
Приведенная выше команда могла быть просто заголовком filename.txt (без <).
Дело не в том, что перенаправление stdin совершенно бесполезно. Некоторые команды полагаются на это. Возьмите команду tr, например. Эта команда может многое, но в приведенном ниже примере она преобразует входной текст из нижнего в верхний регистр:
tr a-z A-Z < filename.txt
На самом деле, использование stdin рекомендуется по конвейеру, чтобы избежать ненужного использования команды cat.
Например, многие люди используют приведенный выше пример с cat, а затем используют tr на нем. Честно говоря, здесь нет необходимости использовать cat.
cat filename.txt | tr a-z A-Z
Объединить перенаправления
Вы можете комбинировать перенаправление stdin, stdout и pipe в соответствии с вашими потребностями.
Например, приведенная ниже команда перечисляет все файлы .txt в текущем каталоге, а затем подсчитывает эти файлы .txt и сохраняет выходные данные в новый файл.
ls *.txt | wc -l > count.txt
Перенаправление ошибок
Иногда, когда вы запускаете какую-либо команду или скрипт, вы видите, что на экране отображается сообщение об ошибке.
andreyex@destroyer:~$ ls -l ffffff > output.txt ls: cannot access 'ffffff': No such file or directory
В начале этой статьи мы упоминали, что существует три потока данных, и stderr – это один из потоков выходных данных, который отображается на экране по умолчанию.
Вы также можете перенаправить stderr. Поскольку это поток выходных данных, вы можете использовать тот же символ перенаправления > или >>, который вы использовали для перенаправления стандартного вывода.
Но как вы различаете stdout и stderr, когда они оба являются потоком выходных данных? По их идентификатору потока (также называется дескриптором файла).
Поток данных | Идентификатор потока |
stdin | 0 |
stdout | 1 |
stderr | 2 |
По умолчанию, когда вы используете выходной символ перенаправления >, это фактически означает 1>. Словом, вы говорите, что здесь выводится поток данных с ID 1.
Когда вам нужно перенаправить stderr, вы используете его идентификатор как 2> или 2>>. Это означает, что перенаправление вывода для потока данных stderr (ID 2).
Примеры перенаправления Stderr
Позвольте нам показать вам несколько примеров. Предположим, вы просто хотите сохранить ошибку, вы можете использовать что-то вроде этого:
andreyex@destroyer:~$ ls fffff 2> error.txt andreyex@destroyer:~$ cat error.txt ls: cannot access 'fffff': No such file or directory
Это было просто. Давайте сделаем это немного более сложным (и полезным):
andreyex@destroyer:~$ ls -l new.txt ffff > output.txt 2> error.txt andreyex@destroyer:~$ cat output.txt -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt andreyex@destroyer:~$ cat error.txt ls: cannot access 'ffff': No such file or directory
В приведенном выше примере команда ls пытается отобразить два файла. Для одного файла она получает успех, а для другого – ошибку. Поэтому мы перенаправили stdout в ouput.txt (с>), а stderr в error.txt (с 2>).
Вы также можете перенаправить как stdout, так и stderr в один и тот же файл. Есть способы сделать это.
В приведенном ниже примере мы сначала отправляем stderr (с 2 >>) в файл комбинированный .txt в режиме добавления. Затем стандартный вывод (с >>) отправляется в тот же файл в режиме добавления.
andreyex@destroyer:~$ ls -l new.txt fff 2>> combined.txt >> combined.txt andreyex@destroyer:~$ cat combined.txt ls: cannot access 'fff': No such file or directory -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt
Другой способ, и он является предпочтительным, состоит в том, чтобы использовать что-то вроде 2>&1. Что можно примерно перевести как «перенаправить stderr на тот же адрес, что и stdout».
Давайте возьмем предыдущий пример и на этот раз используем 2>&1 для перенаправления как stdout, так и stderr в один и тот же файл.
andreyex@destroyer:~$ ls -l new.txt fff > output.txt 2>&1 andreyex@destroyer:~$ cat output.txt ls: cannot access 'fff': No such file or directory -rw-rw-r-- 1 andreyex andreyex 0 May 5 10:12 new.txt
Имейте в виду, что вы не можете использовать 2>>&1, думая об использовании его в режиме добавления. 2>&1 уже переходит в режим добавления.
Вы также можете сначала использовать 2>, а затем 1>&2, чтобы перенаправить стандартный вывод в тот же файл, что и стандартный вывод. По сути, это «>&», который перенаправляет один поток данных в другой.
Резюме
- Есть три потока данных. Один вход, stdin (0) и два потока выходных данных stdout (1) и stderr (2).
- Клавиатура является стандартным устройством ввода, а экран является устройством вывода по умолчанию.
- Перенаправление вывода используется с > или >> (для режима добавления).
- Перенаправление ввода используется с <.
- Stderr может быть перенаправлен с помощью 2> или 2>>.
- Stderr и stdout можно комбинировать, используя 2>&1.
Надеюсь, вам понравилось эта подробная статья по перенаправлению в Linux. Если у вас все еще есть сомнения или у вас есть предложения по улучшению этой статьи, сообщите нам об этом в разделе комментариев.