Почему << (here document) и <<< (here string) нельзя использовать с переменными
Если мы захотим присвоить переменной значение с помощью рассмотренных операторов и попробуем выполнить:
a <<< 'just a string'
или
a <<< _EOF_
то будет получена ошибка:
bash: a: команда не найдена
Причина в том, что нельзя присвоить значение переменным передав данные в стандартном вводе. Например команда
Cmd: как передать файл перенаправления bat файла на что-то вроде /dev/null?
Каждая папка имеет nul-устройство. Это одно из зарезервированных имен. Они могут использоваться в командах для обращения к устройствам. Например:
copy filename con
копирует файл в окно консоли.
Вот зарезервированные имена, определенные CMD:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4,
COM5, COM6, COM7, COM8, COM9, LPT1, LPT2,
LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9
CONIN$, CONOUT$, CONERR$
&>
Последние версии bash предоставляют второй, более упрощённый метод для выполнения комбинированного перенаправления 2>&1:
ls -l /bin/usr &> ls-output.txt
В этом примере мы используем одинарную запись &> для перенаправления как стандартного вывода, так и стандартной ошибки в файл ls-output.txt.
&>>
Вы также можете добавить стандартные выходные данные и стандартные потоки ошибок в один файл, например так:
ls -l /bin/usr &>> ls-output.txt
Итак, &> является аналогом 2>&1, а &>> это то же самое, но с перенаправлением вывода в файл.
> /dev/null
Это частный случай перенаправления, когда всё из стандартного вывода перенаправляется в псевдоустройство /dev/null. Это означает уничтожение данные. То есть ничего не будет выводиться в стандартный вывод.
>>
Функция оператора >> похожа на > с тем отличием, что оператор >> не удаляет содержимое файла, а дописывает новые данные к уже существующим.
Если файл не существует, то оператор >> создаст его и запишет в него переданные данные.
>(команда)
Это ещё одна форма «подстановки процессов» (Process Substitution):
>(КОМАНДА)
Если используется эта форма, то вместо записи в файл, данные будут переданы на ввод для КОМАНДЫ.
< <(команда аргументы)
Данная конструкция состоит из двух уже рассмотренных ранее элементов языка Bash:
Как мы только что узнали, <(КОМАНДА АРГУМЕНТЫ) возвращает имя файла из которого нужно считывать результат выполнения КОМАНДЫ. А оператор < передаёт ввод с файла (указанного справа от него) команде на стандартный ввод (указанной слева).
Следующие две команды являются аналогами друг друга:
grep drw < <(ls -l) ls -l | grep drw
Практический пример использования из статьи «Как обработать каждую строку, полученную от команды grep»:
<<
Оператор << называется here document. С его помощью можно ввести строку состоящую из нескольких строк или присвоить переменной многострочное значение.
Если в консоль ввести
a=строка
и нажать Enter, то переменной a будет присвоено значение «строка» и вновь станет доступно приглашение командной строки, потому что Enter по умолчанию является разделителем, символом новой строки. Из-за этого не получится ввести многострочное значение.
Оператор << (here document) меняет это правило — обозначением для новой строки становится другая последовательность символов. В качестве такого обозначения можно выбрать любой набор символов, единственное условие — этот набор не должен встречаться в водимых данных.
К примеру:
cat <<_EOF_
Данная запись означает, что запущена команда cat, после неё идёт оператор << и последовательность символов _EOF_. Эти символы (_EOF_) Enter означают, что _EOF_ – становится обозначением начала и конца для многострочных данных.
Второй ввод _EOF_ Enter означает конец многострочных данных. После этого будет выполнена команда, то есть будут выведены введённые цифры:
cat <<_EOF_ 1 2 3 _EOF_
Если вы хотите переменной присвоить многострочное значение, то это можно сделать примерно так:
a=`cat <<_EOF_ 1 2 3 _EOF_ `
Выведем значение переменной:
<<<
Оператор <<< называется here string. Он передаёт с правой стороны стандартный ввод. Чтобы было понятно, следующие команды эквивалентны:
wc <<< 'just a string' 1 3 14 'just a string' | wc 1 3 14
<(команда)
Конструкция <(КОМАНДА) называется «подстановка процессов» (Process Substitution). В качестве КОМАНДА может быть одна или более команд с аргументами. Конструкция
вернёт имя специального файла, прочитав который можно получить вывод КОМАНДЫ.
К примеру:
2> >(команда) > /dev/null
Эка комбинация, включающая в себя 3 уже рассмотренных элемента:
- 2> означает перенаправление стандартного вывода ошибок (stderr)
- >(КОМАНДА) означает подстановку процессов, в результате стандартный вывод ошибок будет передан для обработки в КОМАНДУ
- > /dev/null означает перенаправления стандартного вывода в /dev/null, то есть фактическое уничтожение стандартного вывода
Пример практического использования:
curl -v 100.19.18.59 2> >(grep -o -i -E '401 Unauthorized') > /dev/null
Cat > файл <<_eof_
Эта конструкция может показаться очень замысловатой, но она состоит из двух уже рассмотренных элементов:
- > (перенаправление вывода в файл)
Рассмотрим пример:
cat > ФАЙЛ <<_EOF_ foo bar bar bar foo foo _EOF_
В результате выполнения этого кода, в ФАЙЛ будут записаны строки
foo bar bar bar foo foo
Причём если ФАЙЛ уже существует, то он будет стёрт и заменён указанным содержимым.
То есть это один из способов сохранения в файл многострочного вывода.
Cat >> файл <<_eof_
Эта конструкция похожа на предыдущую, в ней используются
- >> (перенаправление вывода в файл с дописыванием данных)
В результате выполнения следующего кода:
cat >> ФАЙЛ <<_EOF_ foo bar bar bar foo foo _EOF_
В ФАЙЛ будут сохранены строки:
foo bar bar bar foo foo
Причём если ФАЙЛ уже существует, то он будет дописан.
Cat <<_eof_ > файл
Данная конструкция получает многострочный ввод по стандартному вводу и сохраняет его в файл. То есть это аналог
cat > ФАЙЛ <<_EOF_
в котором просто операторы поменяны местами.
К примеру, в следующем примере:
cat <<_EOF_ > num.txt 12345 67890 1011121314 _EOF_
В файл num.txt будут сохранены строки
12345 67890 1011121314
Cat <<_eof_ >> файл
Эта запись является аналогом
cat >> ФАЙЛ <<_EOF_
Следующим код
cat <<_EOF_ >> num.txt 12345 67890 1011121314 _EOF_
допишет файл num.txt строками
12345 67890 1011121314
Связанные статьи:
В чём различие << (here document) и <<< (here string)
Различие между этими операторами в том, что << передаёт многострочные данные, которые обрамляются указанной последовательностью символов, а <<< передаёт только строку.
Дублирование дескрипторов
Оператор перенаправления «&» дублирует выходные или входные данные с одного заданного дескриптора на другой заданный дескриптор. Например, для отправки выводных данных команды dir в файл File.txt и отправки ошибки вывода в файл File.txt введите:
dir>c:file.txt 2>&1
При дублировании дескриптора происходит копирование всех его исходных характеристик. Например, если дескриптор доступен только для записи, то все его дубликаты будут доступны только для записи. Нельзя продублировать дескриптор с доступом только для чтения в дескриптор с доступом только для записи.
Использование оператора «>&» для перенаправления ввода и дублирования
При перенаправлении вывода в файл и задании существующего имени файла интерпретатор команд Cmd.exe открывает файл с доступом только для записи и переписывает его содержимое. Если дескриптор задан, интерпретатор команд Cmd.exe дублирует файл в существующий дескриптор.
Для дублирования определенного пользователем дескриптора 3 в дескриптор 1 введите:
>&3
Для перенаправления всех выходных данных, включая выходные данные дескриптора 2 (STDERR), команды ipconfig в дескриптор 1 (STDOUT) и последующего перенаправления выходных данных в Output.log введите:
ipconfig.exe>>output.log 2>&1
Использование оператора «<&» для перенаправления ввода и дублирования
Для использования оператора перенаправления ввода необходимо, чтобы задаваемый файл уже существовал. Если файл для ввода существует, то интерпретатор команд Cmd.exe открывает его с доступом только для чтения и его содержимое отправляет в команду так, как если бы это был ввод с цифровой клавиатуры. При задании дескриптора интерпретатор команд Cmd.exe дублирует его в дескриптор, существующий в системе.
Например, для считывания файла File.txt на вход в дескриптор 0 (STDIN) введите:
Для открытия файла File.txt, сортировки его содержимого и последующей отправки в окно командной строки (STDOUT) введите:
sort<file.txt
Для того чтобы найти файл File.txt и перенаправить дескриптор 1 (STDOUT) и дескриптор 2 (STDERR) в Search.txt введите:
findfile file.txt>search.txt 2<&1
Для дублирования определенного пользователем дескриптора 3 в качестве входной информации для дескриптора 0 (STDIN) введите:
Использование оператора канала (|)
Оператор канала «вертикальная линия» (|) забирает выходные данные одной команды (по умолчанию STDOUT) и направляет их на вход другой команды (по умолчанию STDIN). Например, следующая команда сортирует каталог:
dir | sort
В данном примере обе команды запускаются одновременно, но команда sort приостанавливает работу до получения выходных данных команды dir. Команда sort использует выходные данные команды dir в качестве своих входных данных, а затем свои выходные данные отправляет в дескриптор 1 (STDOUT).
Операторы перенаправления
В следующей таблице описаны операторы перенаправления потоков ввода и вывода команд.
По умолчанию, входные данные команды (дескриптор STDIN) отсылаются с клавиатуры интерпретатору команд Cmd.exe, далее Cmd.exe отправляет выходные данные команды (дескриптор STDOUT) в окно командной строки.
В следующей таблице представлены доступные дескрипторы.
Номера от 0 до 9 представляют первые 10 дескрипторов. Для запуска программы и перенаправления любого из 10 дескрипторов используется интерпретатор команд Cmd.exe. Для задания требуемого дескриптора перед оператором перенаправления введите его номер. Если дескриптор не определен, то по умолчанию оператором перенаправления ввода «<
Для задания перенаправления в существующие дескрипторы используется амперсанд (&), затем номер требуемого дескриптора (например, &номер_дескриптора). Например, для перенаправления дескриптора 2 (STDERR) в дескриптор 1 (STDOUT) введите 1<&2
Перенаправление ввода команд (<)
Для перенаправления ввода команд с цифровой клавиатуры на файл или на устройство используйте оператор «<». Например, для ввода команды sort из файла List.txt введите:
sort<file.txt
Содержимое файла File.txt появится в командной строке в виде списка в алфавитном порядке.
Оператор «<» открывает заданное имя файла с доступом только для чтения. Поэтому с его помощью нельзя записывать в файл. Например, при запуске программы с оператором <&2 все попытки прочитать дескриптор 0 ни к чему не приведут, так как изначально он был открыт с доступом только для записи.
Примечание: Дескриптор 0 задан по умолчанию для оператора перенаправления ввода «<».
Перенаправление стандартного потока ввода
Используя знак
вместо
>
мы можем перенаправить стандартный ввод, заменив его содержимым файла.
Предположим, имеется два файла: list1.txt и list2.txt, каждый из которых содержит неотсортированный список строк. В каждом из списков имеются уникальные для него элементы, но некоторые из элементов список совпадают. Мы можем найти строки, которые имеются и в первом, и во втором списках, применив команду comm, но прежде чем её использовать, списки надо отсортировать.
Существует команда sort, которая возвращает отсортированный список в терминал, не сохраняя отсортированные данные в файл, из которого они были взяты. Можно отправить отсортированную версию каждого списка в новый файл, используя команду >, а затем воспользоваться командой comm.
Итак, мы можем воспользоваться командой < для перенаправления отсортированной версии каждого файла команде comm. Вот что у нас получилось:
$ comm <(sort list1.txt) <(sort list2.txt)
Круглые скобки тут имеют тот же смысл, что и в математике. Оболочка сначала обрабатывает команды в скобках, а затем всё остальное. В нашем примере сначала производится сортировка строк из файлов, а потом то, что получилось, передаётся команде
comm
, которая затем выводит результат сравнения списков.
Перенаправление стандартного потока ошибок
И, наконец, поговорим о перенаправлении стандартного потока ошибок. Это может понадобиться, например, для создания лог-файлов с ошибками или объединения в одном файле сообщений об ошибках и возвращённых некоей командой данных.
Например, что если надо провести поиск во всей системе сведений о беспроводных интерфейсах, которые доступны пользователям, у которых нет прав суперпользователя? Для того, чтобы это сделать, можно воспользоваться мощной командой find.
Обычно, когда обычный пользователь запускает команду find по всей системе, она выводит в терминал и полезные данные и ошибки. При этом, последних обычно больше, чем первых, что усложняет нахождение в выводе команды того, что нужно. Решить эту проблему довольно просто: достаточно перенаправить стандартный поток ошибок в файл, используя команду 2>
$ find / -name wireless 2> denied.txt
Как быть, если нужно сохранить результаты работы команды в отдельный файл, не смешивая эти данные со сведениями об ошибках? Так как потоки можно перенаправлять независимо друг от друга, в конец нашей конструкции можно добавить команду перенаправления стандартного потока вывода в файл:
$ find / -name wireless 2> denied.txt > found.txt
Обратите внимание на то, что первая угловая скобка идёт с номером —
2>
, а вторая без него. Это так из-за того, что стандартный вывод имеет дескриптор 1, и команда
>
подразумевает перенаправление стандартного вывода, если номер дескриптора не указан.
И, наконец, если нужно, чтобы всё, что выведет команда, попало в один файл, можно перенаправить оба потока в одно и то же место, воспользовавшись командой &>:
$ find / -name wireless &> results.txt
Итоги
Тут мы разобрали лишь основы механизма перенаправления потоков в интерпретаторе командной строки Linux, однако даже то немногое, что вы сегодня узнали, даёт вам практически неограниченные возможности. И, кстати, как и всё остальное, что касается работы в терминале, освоение перенаправления потоков требует практики. Поэтому рекомендуем вам приступить к собственным экспериментам с
>
Уважаемые читатели! Знаете ли вы интересные примеры использования перенаправления потоков в Linux, которые помогут новичкам лучше освоиться с этим приёмом работы в терминале?
Три стандартных потока ввода/вывода
Для того, чтобы понять то, о чём мы будем тут говорить, важно знать, откуда берутся данные, которые можно перенаправлять, и куда они идут. В Linux существует три стандартных потока ввода/вывода данных.
Первый — это стандартный поток ввода (standard input). В системе это — поток №0 (так как в компьютерах счёт обычно начинается с нуля). Номера потоков ещё называют дескрипторами. Этот поток представляет собой некую информацию, передаваемую в терминал, в частности — инструкции, переданные в оболочку для выполнения. Обычно данные в этот поток попадают в ходе ввода их пользователем с клавиатуры.
Второй поток — это стандартный поток вывода (standard output), ему присвоен номер 1. Это поток данных, которые оболочка выводит после выполнения каких-то действий. Обычно эти данные попадают в то же окно терминала, где была введена команда, вызвавшая их появление.
И, наконец, третий поток — это стандартный поток ошибок (standard error), он имеет дескриптор 2. Этот поток похож на стандартный поток вывода, так как обычно то, что в него попадает, оказывается на экране терминала. Однако, он, по своей сути, отличается от стандартного вывода, как результат, этими потоками, при желании, можно управлять раздельно.
Это полезно, например, в следующей ситуации. Есть команда, которая обрабатывает большой объём данных, выполняя сложную и подверженную ошибкам операцию. Нужно, чтобы полезные данные, которые генерирует эта команда, не смешивались с сообщениями об ошибках. Реализуется это благодаря раздельному перенаправлению потоков вывода и ошибок.
Как вы, вероятно, уже догадались, перенаправление ввода/вывода означает работу с вышеописанными потоками и перенаправление данных туда, куда нужно программисту. Делается это с использованием символов > и < в различных комбинациях, применение которых зависит от того, куда, в итоге, должны попасть перенаправляемые данные.
Использование оператора «>>» для добавления вывода
Для добавления выходных данных команды в конец файла без потери хранящейся в нем информации используется двойной символ «больше» (>>). Например, следующая команда добавляет список каталогов, созданный командой dir, в файл Dirlist.txt:
dir>>dirlist.txt
Для добавления выходных данных команды netstat в конец файла Tcpinfo.txt введите:
netstat>>tcpinfo.txt
Перенаправление стандартного потока вывода
Предположим, вы хотите создать файл, в который будут записаны текущие дата и время. Дело упрощает то, что имеется команда, удачно названная
date
, которая возвращает то, что нам нужно. Обычно команды выводят данные в стандартный поток вывода. Для того, чтобы эти данные оказались в файле, нужно добавить символ
>
после команды, перед именем целевого файла. До и после
>
надо поставить пробел.
При использовании перенаправления любой файл, указанный после > будет перезаписан. Если в файле нет ничего ценного и его содержимое можно потерять, в нашей конструкции допустимо использовать уже существующий файл. Обычно же лучше использовать в подобном случае имя файла, которого пока не существует.
$ date > date.txt
Нельзя сказать, что сама по себе эта команда невероятно полезна, однако, основываясь на ней, мы уже можем сделать что-то более интересное. Скажем, вы хотите узнать, как меняются маршруты вашего трафика, идущего через интернет к некоей конечной точке, ежедневно записывая соответствующие данные. В решении этой задачи поможет команда
traceroute
, которая сообщает подробности о маршруте трафика между нашим компьютером и конечной точкой, задаваемой при вызове команды в виде URL. Данные включают в себя сведения обо всех маршрутизаторах, через которые проходит трафик.
Так как файл с датой у нас уже есть, будет вполне оправдано просто присоединить к этому файлу данные, полученные от traceroute. Для того, чтобы это сделать, надо использовать два символа >, поставленные один за другим. В результате новая команда, перенаправляющая вывод в файл, но не перезаписывающая его, а добавляющая новые данные после старых, будет выглядеть так: