Операторы перенаправления вывода в Bash
Операторы перенаправления вывода в Bash: что означает &1 и другие
Рассмотрим операторы перенаправления вывода Bash и похожие по функции операторы и конструкции. Я собрал следующий список, если что-то пропустил, то пишите в комментариях:
Этот оператор на английском называется pipe, и на русском его называют труба или конвейер. Используется очень часто для перенаправления вывода из одной команды в другую, которая может принимать стандартный вывод. Например:
Символ > используется для перенаправления вывода в файл, например:
То есть оператор | используется когда вывод передаётся в другую команду, а оператор > используется когда вывод записывается в файл.
Ещё один пример использования сразу обоих операторов:
Результат работы этой последовательности команд будет сохранён в файл num.txt.
Если файл не существует, то он будет создан. Если файл существует, то оператор > полностью удалит его содержимое и запишет новым.
> /dev/null
Это частный случай перенаправления, когда всё из стандартного вывода перенаправляется в псевдоустройство /dev/null. Это означает уничтожение данные. То есть ничего не будет выводиться в стандартный вывод.
Функция оператора >> похожа на > с тем отличием, что оператор >> не удаляет содержимое файла, а дописывает новые данные к уже существующим.
Если файл не существует, то оператор >> создаст его и запишет в него переданные данные.
Оператор 2> перенаправляет стандартный вывод ошибок — standard error (stderr).
Результат выполнения команд и возникшие ошибки выводятся на консоль и может показаться, что это одно и то же. Но на самом деле, это разные типы вывода.
К примеру попытаемся сохранить в файл текст ошибки, возникшей в результате выполнения команды:
Текст ошибки будет выведен на экран, но файл ls-error.txt окажется пустым.
Дело в том, что нужно различать стандартный вывод и стандартный вывод ошибок. Чтобы перенаправить стандартный вывод в файл используется оператор 2>:
В данном случае ошибка не будет выведена на экран, а будет сохранена в файл ls-error.txt.
Чтобы перенаправить стандартную ошибку, мы должны обратиться к её файловому дескриптору. Программа может выводить любой из нескольких пронумерованных файловых потоков. Первые три из этих файловых потоков называются стандартный ввод, стандартный вывод и стандартный вывод ошибок. Оболочка ссылается на них внутренне как файловые дескрипторы 0, 1 и 2 соответственно. Оболочка обеспечивает запись для перенаправления файлов с использованием номера дескриптора файла. Поскольку стандартная ошибка совпадает с дескриптором файла номер 2, мы можем перенаправить стандартную ошибку с помощью 2>.
Файловый дескриптор «2» помещается непосредственно перед оператором перенаправления, чтобы выполнить перенаправление стандартной ошибки в файл ls-error.txt.
Конструкция 2>&1 предназначена для перенаправления стандартного вывода и стандартного вывода ошибок в один файл.
В некоторых случаях мы можем захотеть записать весь вывод команды в один файл. Чтобы сделать это, мы должны одновременно перенаправить как стандартный вывод, так и стандартный вывод ошибок. Есть два способа сделать это. Во-первых, традиционный способ, который работает со старыми версиями оболочки:
Используя этот метод, мы выполняем два перенаправления. Сначала мы перенаправляем стандартный вывод в файл ls-output.txt, а затем перенаправляем дескриптор файла 2 (стандартная вывод ошибок) на дескриптор файла один (стандартный вывод), используя обозначения 2>&1.
Обратите внимание, что порядок перенаправлений является значимым. Перенаправление стандартной ошибки всегда должно происходить после перенаправления стандартного вывода, иначе оно не работает. В приведённом выше примере
перенаправляет стандартную ошибку в файл ls-output.txt, но при изменении порядка на
стандартная ошибка направлена на экран.
Последние версии bash предоставляют второй, более упрощённый метод для выполнения комбинированного перенаправления 2>&1:
В этом примере мы используем одинарную запись &> для перенаправления как стандартного вывода, так и стандартной ошибки в файл ls-output.txt.
Вы также можете добавить стандартные выходные данные и стандартные потоки ошибок в один файл, например так:
Итак, &> является аналогом 2>&1, а &>> это то же самое, но с перенаправлением вывода в файл.
Это ещё одна форма «подстановки процессов» (Process Substitution):
Если используется эта форма, то вместо записи в файл, данные будут переданы на ввод для КОМАНДЫ.
>(КОМАНДА) > /dev/null
Эка комбинация, включающая в себя 3 уже рассмотренных элемента:
Пример практического использования:
HTTP заголовки команда cURL выводит в stderr, а команда grep не ищет по stderr. Но если мы хотим искать только по HTTP заголовков (игнорируя HTML код), то мы не может сделать просто перенаправление stderr для слияния со стандартным выводом, то есть не можем 2>&1, поскольку текст страницы может содержать фразу «401 Unauthorized» и мы получим ложное срабатывание. Поэтому мы используем указанную выше конструкцию — стандартный вывод ошибок обрабатывается, стандартный вывод уничтожается.
Данная конструкция получает многострочный ввод по стандартному вводу и сохраняет его в файл. То есть это аналог
в котором просто операторы поменяны местами.
EOF — это не символ
Если вы читали о системе ввода-вывода Unix/Linux, или экспериментировали с ней, если писали программы на C, которые читают данные из файлов, то это заявление вам, вероятно, покажется совершенно очевидным. Но давайте поближе присмотримся к следующим двум утверждениям, относящимся к тому, что я нашёл в книге:
EOF — это не символ
Это может выглядеть так:
А что такое, вообще, символ? Символ — это самый маленький компонент текста. «A», «a», «B», «b» — всё это — разные символы. У символа есть числовой код, который в стандарте Unicode называют кодовой точкой. Например — латинская буква «A» имеет, в десятичном представлении, код 65. Это можно быстро проверить, воспользовавшись командной строкой интерпретатора Python:
Или можно взглянуть на таблицу ASCII в Unix/Linux:
Скомпилируем и запустим программу:
В конце файлов нет некоего особого символа
Может, EOF — это особенный символ, который можно обнаружить в конце файла? Полагаю, сейчас вы уже знаете ответ. Но давайте тщательно проверим наше предположение.
Возьмём простой текстовый файл, helloworld.txt, и выведем его содержимое в шестнадцатеричном представлении. Для этого можно воспользоваться командой xxd :
Что такое EOF?
EOF (end-of-file) — это состояние, которое может быть обнаружено приложением в ситуации, когда операция чтения файла доходит до его конца.
ANSI C
Начнём с почтенного C. Представленная здесь программа является модифицированной версией cat из книги «Язык программирования C».
Вот некоторые пояснения, касающиеся вышеприведённого кода:
Python 3
Запустим программу и взглянём на возвращаемые ей результаты:
Вот более короткая версия этого же примера, написанная на Python 3.8+. Здесь используется оператор := (его называют «оператор walrus» или «моржовый оператор»):
В Go можно явным образом проверить ошибку, возвращённую Read(), на предмет того, не указывает ли она на то, что мы добрались до конца файла:
JavaScript (Node.js)
Низкоуровневые системные механизмы
Вот эта программа, написанная на C:
Вот та же программа, написанная на Python 3:
Вот — то же самое, написанное на Python 3.8+:
Запустим и этот код:
Итоги
Как работает «cat psql ).
После небольшого поиска я нашел следующий синтаксис:
Но я понятия не имею, как/почему это работает, может кто-нибудь объяснить, пожалуйста?
И есть ли справочная страница для этого?
Это называется формат heredoc для предоставления строки в стандартный ввод. Смотрите https://en.wikipedia.org/wiki/Here_document#Unix_shells для более подробной информации.
Здесь документы
Этот тип перенаправления инструктирует Shell читать входные данные из текущий источник до строки содержащий только Word (без конечных пробелов).
Все строки, прочитанные до этого момента, затем используются как стандартный ввод для команды.
Синтаксис cat очень полезен при работе с многострочным текстом в Bash, например. при назначении многострочной строки переменной Shell, файлу или каналу.
Примеры использования синтаксиса cat в Bash:
1. Присвойте многострочную строку переменной Shell
2. Передать многострочную строку в файл в Bash
Файл print.sh теперь содержит:
3. Передайте многострочную строку в трубу в Bash.
Некоторые правила о тегах Here:
POSIX 7
Конечно, это существует, так что вы можете сделать отступ для своего cat как окружающий код, который легче читать и поддерживать. Например.:
К сожалению, это не работает для пробелов: POSIX предпочитает отступ tab здесь. Хлоп.
Использование тройника вместо кошки
Не совсем как ответ на первоначальный вопрос, но я все равно хотел поделиться этим: мне нужно было создать файл конфигурации в каталоге, который требовал наличия прав root.
Следующее не работает для этого случая:
потому что перенаправление обрабатывается вне контекста Судо.
Я закончил тем, что использовал это вместо этого:
Стоит отметить, что здесь документы также работают в циклах bash. В этом примере показано, как получить список столбцов таблицы:
или даже без новой строки
Это не обязательно ответ на первоначальный вопрос, а обмен некоторыми результатами моего собственного тестирования. Это:
создаст тот же файл, что и:
Так что я не вижу смысла в использовании команды cat.
Частые ошибки программирования на Bash (продолжение)
11. cat file | sed s/foo/bar/ > file
Нельзя читать из файла и писать в него в одном и том же конвейере. В зависимости от того, как построен конвейер, файл может обнулиться (или оказаться усечённым до размера, равному объёму буфера, выделяемого операционной системой для конвейера), или неограниченно увеличиваться до тех пор, пока он не займёт всё доступное пространство на диске, или не достигнет ограничения на размер файла, заданного операционной системой или квотой, и т.д.
Если вы хотите произвести изменение в файле, отличное от добавления данных в его конец, вы должны в какой-то промежуточный момент создать временный файл. Например (этот код работает во всех шеллах):
Следующий фрагмент будет работать только при использовании GNU sed 4.x и выше:
Обратите внимание, что при этом тоже создаётся временный файл и затем происходит переименование — просто это делается незаметно.
В BSD-версии sed необходимо обязательно указывать расширение, добавляемое к запасной копии файла. Если вы уверены в своем скрипте, можно указать нулевое расширение:
Также можно воспользоваться perl 5.x, который, возможно, встречается чаще, чем sed 4.x:
Различные аспекты задачи массовой замены строк в куче файлов обсуждаются в Bash FAQ #21.
Нет, вы не можете создать переменную, поставив «$» в начале её названия. Это не Perl. Достаточно написать:
14. foo = bar
По этой же причине нижеследующие выражения также неправильны:
15. echo EOF ) на входной поток команды. К сожалению, echo не принимает данные с STDIN.
17. cd /foo; bar
Поэтому всегда нужно проверять код возврата команды «cd». Простейший способ:
Если за cd следует больше одной команды, можно написать так:
Вернёмся к нашим баранам. Сравните этот фрагмент:
Принудительный вызов подоболочки заставляет cd и последующие команды выполняться в subshell’е; в следующей итерации цикла мы вернёмся в начальное местонахождение вне зависимости от того, успешной ли была смена директории или же она завершилась с ошибкой. Нам не нужно возвращаться вручную.
18. [ bar == «$foo» ]
Нельзя помещать точку с запятой «;» сразу же после &. Просто удалите этот лишний символ:
Символ & сам по себе является признаком конца команды, так же, как «;» и перевод строки. Нельзя ставить их один за другим.
20. cmd1 && cmd2 || cmd3
Что здесь произошло? По идее, переменная i должна принять значение 1, но в конце скрипта она содержит 0. То есть последовательно выполняются обе команды i++ и i—. Команда ((i++)) возвращает число, являющееся результатом выполнения выражения в скобках в стиле C. Значение этого выражения — 0 (начальное значение i), но в C выражение с целочисленным значением 0 рассматривается как false. Поэтому выражение ((i++)), где i равно 0, возвращает 1 (false) и выполняется команда ((i—)).
Этого бы не случилось, если бы мы использовали оператор преинкремента, поскольку в данном случае код возврата ++i — true:
Bourne shell это тоже касается:
21. Касательно UTF-8 и BOM (Byte-Order Mark, метка порядка байтов)
В общем: в Unix тексты в кодировке UTF-8 не используют метки порядка байтов. Кодировка текста определяется по локали, mime-типу файла, или по каким-то другим метаданным. Хотя наличие BOM не испортит UTF-8 документ в плане его читаемости человеком, могут возникнуть проблемы с автоматической интерпретацией таких файлов в качестве скриптов, исходных кодов, файлов конфигурации и т.д. Файлы, начинающиеся с BOM, должны рассматриваться как чужеродные, так же как и файлы с DOS’овскими переносами строк.
Что такое Cat EOF в Bash Script?
Главное меню » Linux » Mint » Что такое Cat EOF в Bash Script?
Обычно он используется либо для печати текста файла в терминале, либо для копирования содержимого файла в другое указанное место. Команда cat, за которой следует имя файла, позволяет просматривать содержимое любого файла в терминале Linux. Однако вместо того, чтобы выполнять этот шаг для просмотра содержимого файла, мы можем просто включить этот шаг в наш сценарий bash для той же цели. В этой статье показано использование оператора Cat EOF в сценарии bash в Linux Mint 20 с примерами.
Два случая использования Cat EOF в Bash Script в Linux Mint 20
Чтобы объяснить использование оператора Cat EOF в сценарии bash, мы разработали два простых примера сценария использования этого оператора в Linux Mint 20. Мы рассмотрим эти сценарии один за другим.
Случай №1: Печать содержимого файла в терминале
В этом сценарии мы покажем вам, как использовать оператор EOF для печати содержимого файла в терминале. Для этого мы сначала создадим сценарий bash, который будет содержать образец текста. Когда этот сценарий bash выполняется, он будет отображать текст, заключенный в нашем сценарии bash, в терминале. Следуйте инструкциям ниже, чтобы распечатать содержимое любого заданного файла в вашем терминале.
Шаг 1. Создайте сценарий Bash
Сначала мы создадим файл с именем EOF.sh в нашем домашнем каталоге. Вы можете выбрать любое другое имя для этого файла bash. Кроме того, вы можете создать этот файл bash в любом каталоге по вашему выбору; однако всегда удобно создавать файлы в домашнем каталоге в демонстрационных целях. Это избавляет нас от необходимости указывать путь к файлу каждый раз, когда мы хотим получить к нему доступ.
Шаг 3: проанализируйте вывод Bash Script
После выполнения команды на шаге 2 вы увидите содержимое, заключенное в блок cat Читать 7 Забавных команд в Linux
Шаг 2: выполнение сценария Bash
Когда наш сценарий bash был изменен, пришло время выполнить его с той же командой, что и в случае № 1. Однако на этот раз вы не сможете ничего увидеть на терминале.
Шаг 3. Проанализируйте содержимое файла, в который был скопирован образец текста
Чтобы проверить, успешно ли была выполнена желаемая операция, сначала мы перейдем в наш домашний каталог. В домашнем каталоге мы попытаемся найти файл, в который мы хотели скопировать содержимое нашего сценария bash. Как только файл будет найден (в нашем случае имя файла было «temp.txt»), вы можете просто открыть его, чтобы просмотреть его содержимое. Содержимое нашего файла является точной копией содержимого, заключенного в нашем сценарии bash.
Заключение
Пройдя два сценария, представленных в этой статье, вы должны быть в состоянии сказать, что понимаете базовое использование Cat EOF в сценарии bash в Linux Mint 20. Эти сценарии предоставляют вам два разных способа использования этого оператора в Linux Mint 20. для печати содержимого файла или копирования содержимого одного файла в другой.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.




