|
Навигация
|
Главная » Linux Изучаем Linux, 101: Потоки, программные каналы и перенаправленияИсточник: IBM Краткий обзорИз этой статьи вы узнаете об основных приемах перенаправления стандартных потоков ввода/вывода в Linux. Вы научитесь:
Необходимые условия Чтобы извлечь наибольшую пользу из наших статей, необходимо обладать базовыми знаниями о Linux и иметь работоспособный компьютер с Linux, на котором можно будет выполнять все встречающиеся команды. Иногда различные версии программ выводят результаты по-разному, поэтому содержимое листингов и рисунков может отличаться от того, что вы увидите на вашем компьютере. Подготовка к выполнению примеров Для выполнения примеров в этой статье мы будем использовать некоторые файлы, созданные ранее в статье "Изучаем Linux, 101: текстовые потоки и фильтры". Если вы не читали эту статью или не сохранили эти файлы, не расстраивайтесь! Давайте начнем с создания новой директории lpi103-4 и всех необходимых файлов. Для этого откройте текстовое окно и перейдите в вашу домашнюю директорию. Скопируйте содержимое листинга 1 в текстовое окно; в результате выполнения команд в вашей домашней директории будет создана поддиректория lpi103-4 и все необходимые файлы в ней, которые мы и будем использовать в наших примерах. Листинг 1. Создание файлов, необходимых для примеров этой статьи
Ваше окно должно выглядеть так, как показано в листинге 2, а вашей текущей рабочей директорией должна стать вновь созданная директория lpi103-4. Листинг 2. Результаты создания необходимых файлов
Командный интерпретатор Linux, такой как Bash, получает входные данные и направляет выходные данные в виде последовательностей или потоков символов. Любой символ не зависит ни от предыдущих, ни от последующих символов. Символы не упорядочены в виде структурированных записей или блоков с фиксированным размером. Доступ к потокам осуществляется с помощью механизмов ввода/вывода независимо от того, откуда поступают и куда передаются потоки символов (файл, клавиатура, окно, экран или другое устройство ввода/вывода). Командные интерпретаторы Linux используют три стандартных потока ввода/вывода, каждому из которых назначен определенный файловый дескриптор.
Если вы уже прочитали руководство "Изучаем Linux, 101: текстовые потоки и фильтры", то часть материала из этой статьи окажется вам знакомой. Перенаправление вывода Существует два способа перенаправления вывода в файл:
ls с использованием файлов, которые были созданы ранее в директории lpi103-4. Также продемонстрировано добавление вывода команды в существующие файлы.Листинг 3. Перенаправление вывода
Мы уже говорили, что перенаправление вывода с помощью оператора n> обычно приводит к перезаписи существующих файлов. Вы можете управлять этим свойством при помощи опции noclobber встроенной команды set . Если эта опция определена, то вы можете переопределить ее с помощью оператора n>/, как показано в листинге 4.Листинг 4. Перенаправление вывода с помощью опции noclobber
Иногда может потребоваться перенаправить в файл как стандартный вывод, так и стандартный поток ошибок. Часто это используется в автоматизированных процессах или фоновых заданиях для того, чтобы впоследствии можно было просмотреть результаты работы. Чтобы перенаправить стандартный вывод и стандартный поток ошибок в одно и то же место, используйте оператор &> или &>>. Альтернативный вариант - перенаправить файловый дескриптор n и затем файловый дескриптор m в одно и то же место с помощью конструкции m>&n или m>>&n. В этом случае важен порядок перенаправления потоков. Например, команда command 2>&1 >output.txt это не то же самое, что команда command >output.txt 2>&1 В первом случае поток ошибок stderr перенаправляется в текущее месторасположение потока stdout, а затем поток stdout перенаправляется в файл output.txt; однако второе перенаправление затрагивает только stdout, но не stderr. Во втором случае поток stderr перенаправляется в текущее месторасположение потока stdout, то есть, в файл output.txt. Эти перенаправления проиллюстрированы в листинге 5. Обратите внимание на последнюю команду, в которой стандартный вывод был перенаправлен после стандартного потока ошибок, и, как следствие, поток ошибок продолжает выводиться в окно терминала. Листинг 5. Перенаправление двух потоков в один файл
В других ситуациях вам может потребоваться полностью проигнорировать стандартный вывод или стандартный поток ошибок. Для этого следует перенаправить соответствующий поток в пустой файл /dev/null. В листинге 6 показано, как проигнорировать поток ошибок команды ls и как с помощью команды cat убедиться в том, что файл /dev/null на самом деле пуст.Листинг 6. Игнорирование стандартного потока ошибок посредством использования /dev/null
Перенаправление ввода Так же, как мы можем перенаправить потоки stdout и stderr, мы можем перенаправить поток stdin из файла с помощью оператора <. Если вы прочли руководство "Изучаем Linux, 101: текстовые потоки и фильтры", то должны помнить, что в разделе Команды sort и uniq была использована команда tr для замены пробелов в файле text1 на символы табуляции. В том примере мы использовали вывод команды cat чтобы создать стандартный поток ввода для команды tr . Теперь для преобразования пробелов в символы табуляции вместо бесполезного вызова команды cat мы можем использовать перенаправление ввода, как показано в листинге 7.Листинг 7. Перенаправление ввода
В командных интерпретаторах, в том числе и в bash, реализована концепция here-document , которая является одним из способов перенаправления ввода. В ней используется конструкция << и какое-либо слово, например END, являющееся маркером, или сигнальной меткой, означающей конец ввода. Эта концепция продемонстрирована в листинге 8. Листинг 8. Перенаправление ввода с использованием концепции here-document
Но почему нельзя просто набрать команду sort -k2 , ввести данные и нажать комбинацию Ctrl-d, означающую конец ввода? Разумеется, вы могли бы выполнить эту команду, но тогда вы не узнали бы о концепции here-document, которая очень часто используется в сценариях командной оболочки (в которых не существует другой возможности указать, какие именно строки должны восприниматься в качестве ввода). Поскольку для выравнивания текста и обеспечения удобства чтения в сценариях широко используются символы табуляции, существует другой прием использования концепции here-document. При использовании оператора <<- вместо оператора << начальные символы табуляции удаляются.В листинге 9 мы использовали подстановку команд для создания символа табуляции, а затем создали небольшой сценарий командной оболочки, содержащий две команды cat , каждая из которых считывает данные из блока here-document. Заметьте, что мы использовали слово END в качестве сигнальной метки блока here-document, который мы считываем с терминала. Если бы мы использовали это же слово в нашем сценарии, то наш ввод закончился бы преждевременно. Поэтому вместо слова END мы используем в сценарии слово EOF. После того, как наш сценарий создан, мы используем команду . (точка) чтобы запустить его в контексте текущего командного интерпретатора.Листинг 9. Перенаправление ввода с использованием концепции here-document
В следующих статях этой серии вы узнаете больше о подстановке команд и сценариях. Создание конвейеров В статье "Изучаем Linux, 101: текстовые потоки и фильтры" мы рассказывали о фильтрации как о процессе, в котором входной поток текста определенным образом преобразовывается и передается в выходной поток. Чаще всего такая фильтрация осуществляется через создание конвейера команд, в котором вывод одной команды перенаправляется на вход следующей команды. Подобное использование конвейеров не ограничено только текстовыми потоками, хотя чаще всего они применяются именно для работы с текстом. Передача stdout в stdin Оператор / (конвейеризация) помещается между двумя командами для направления потока stdout первой команды в поток stdin второй команды. Можно составлять более длинные конвейеры, добавляя дополнительные команды и операторы конвейеризации. Любая из команд может иметь опции или аргументы. Аргументом многих команд может являться не имя файла, а знак дефиса (-), который означает, что входные данные следует принимать со стандартного устройства ввода, а не из файла. Для полной уверенности вы можете обращаться к man-страницам нужной вам команды. Построение длинных конвейеров из команд, каждая из которых имеет свой ограниченный функционал - это распространенный в Linux и UNIX® прием, используемый для решения поставленных задач. В нашем гипотетическом конвейере (листинг 10) команды command2 и command3 имеют параметры, а команда command3 использует параметр - , означающий ввод данных с устройства stdin.Листинг 10. Конвейеризация вывода через несколько команд
Необходимо заметить, что эти конвейеры передают только поток stdout в поток stdin. Вы не можете использовать оператор 2/ для передачи потока stderr, по крайней мере с помощью тех инструментов, о которых вам известно к этому моменту. Если поток stderr был перенаправлен в поток stdout, то оба потока будут переданы по конвейеру. В листинге 11 приведен пример, в котором сначала используется команда ls с четырьмя аргументами, содержащими групповые символы и расположенными не в алфавитном порядке, а затем с помощью конвейера сортируются сообщения об ошибках и обычный вывод.Листинг 11. Конвейер из двух потоков вывода
Одним из преимуществ конвейеров в Linux и UNIX является то, что, в отличие от некоторых других популярных операционных систем, в конвейерах Linux не используются никакие промежуточные файлы. Стандартный поток вывода первой команды не записывается в файл, который потом считывается второй командой. Из руководства "Изучаем Linux, 101: управление файлами и директориями" вы уже знаете, как можно одновременно заархивировать и сжать файл с помощью команды tar . Если вам придется работать в операционной системе UNIX, в которой команда tar не имеет опции -z (сжатие с использованием gzip) или -j (сжатие с использованием bzip2), то это не беда. Для этого вы можете использовать, например, такой конвейер: bunzip2 -c somefile.tar.bz2 / tar -xvf - Создание конвейера, первым элементом которого является файл, а не поток stdout Конвейеры, которые мы рассматривали выше, начинались с некоторой команды, генерирующей вывод, который, в свою очередь, передавался через каждый этап конвейера. Но что делать, если мы захотим начать наш конвейер с уже существующего файла, содержащего нужные данные? Это очень легко осуществить, поскольку многие команды могут принимать данные как со стандартного устройства ввода, так и из файлов. Если же используемый вами фильтр требует ввода данных с устройства stdin, то можно использовать команду cat для копирования содержимого файла в поток stdout. Этот способ сработает. Однако более распространенным решением является перенаправление ввода для первой команды и передача ее вывода через все остальные этапы конвейера. Для перенаправления потока stdin вашей первой команды в файл, который вы хотите обрабатывать, просто используйте оператор <.Использование вывода в качестве аргументов Из предыдущего материала нашей статьи вы узнали, как можно получить вывод одной команды и использовать его в качестве входных данных другой команды. Предположим теперь, что вы хотите использовать вывод команды или содержимое файла в качестве аргументов (а не входных данных) другой команды. В этом случае конвейеры вам не помогут, однако существуют три распространенных способа сделать это:
Использование команды xargs Команда xargs считывает данные со стандартного устройства ввода, а затем строит и выполняет команды, параметрами которых являются полученные входные данные. Если не указана никакая команда, то используется команда echo . В листинге 12 приведен простой пример использования нашего файла text1, содержащего три строки по два слова в каждой.Листинг 12. Использование команды xargs
Почему же тогда вывод xargs содержит только одну строку? По умолчанию xargs разбивает входные данные, если встречает символы-разделители, и каждый полученный фрагмент становится отдельным параметром. Однако когда xargs строит команду, ей за один раз передается максимально возможное количество параметров. Это поведение можно изменить с помощью параметра -n или --max-args . В листинге 13 приведен пример использования обоих вариантов; также был выполнен явный вызов команды echo для использования с xargs .Листинг 13. Использование команд xargs и echo
Если входные данные содержат пробелы, но при этом они заключены в одиночные или двойные кавычки (либо пробелы представлены в виде escape-последовательностей с использованием обратной косой черты), то xargs не будет разбивать их на отдельные части. Это показано в листинге 14.Листинг 14. Использование команды xargs и кавычек
До сих пор все аргументы добавлялись в конец команды. Если вам необходимо, чтобы после них были добавлены другие дополнительные аргументы, то воспользуйтесь опцией -I для указания строки замещения. В том месте вызываемой через xargs команды, в котором используется строка замещения, вместо нее будет подставлен аргумент. При использовании такого подхода каждой команде передается только один аргумент. Однако аргумент будет создан из целой входной строки, а не из отдельного ее фрагмента. Также вы можете использовать опцию -L команды xargs , в результате чего в качестве аргумента будет использоваться вся строка целиком, а не отдельные ее фрагменты, разделенные пробелами. Использование опции -I неявно вызывает использование опции -L 1 . В листинге 15 приведены примеры использования опций -I и -L .Листинг 15. Использование команды xargs и строк ввода
Хотя в наших примерах используются простые текстовые файлы, вы не будете часто использовать команду xargs для таких случаев. Как правило, вы будете иметь дело с большим списком файлов, полученных в результате выполнения таких команд, как ls , find или grep . В листинге 16 показан один из способов передачи через xargs списка содержимого директории такой команде, как, например, grep .Листинг 16. Использование команды xargs и списка файлов
Что произойдет в последнем примере, если одно или несколько имен файлов будут содержать пробелы? Если вы попытаетесь использовать команду так, как это было сделано в листинге 16, то вы получите ошибку. В реальной ситуации список файлов может быть получен не от команды ls , а, например, в результате выполнения пользовательского сценария или команды; а может быть, вы захотите обработать его на других этапах конвейера с целью дополнительной фильтрации. Поэтому мы не берем во внимание тот факт, что вы могли бы просто использовать команду grep "1" * вместо существующей логической структуры.В случае с командой ls вы могли бы использовать опцию --quoting-style для того, чтобы имена файлов, содержащие пробелы, были заключены в скобки (или представлены в виде escape-последовательностей). Лучшим решением (когда это возможно) является использование опции -0 команды xargs , в результате чего для разделения входных аргументов используются пустые символы (\0). Хотя команда ls не имеет опции, позволяющей использовать в качестве вывода имена файлов с завершающим нулем, многие команды умеют делать это.В листинге 17 мы сначала скопируем файл text1 в "text 1", а затем приведем несколько примеров использования списка имен файлов, содержащих пробелы, с командой xargs . Эти примеры позволяют понять саму идею, поскольку полностью освоить работу с xargs может оказаться не так просто. В частности, последний пример преобразования символов новой строки в пустые символы не сработал бы в том случае, если некоторые имена файлов уже содержали бы символы новой строки. В следующем разделе этой статьи мы рассмотрим более надежное решение с применением команды find для генерации подходящего вывода, в котором в качестве разделителей используются пустые символы.Листинг 17. Использование команды xargs и файлов, содержащих пробелы в именах
Команда xargs не может строить сколь угодно длинные команды. Так, в Linux до версии ядра 2.26.3 максимальная длина команды была ограничена. Если вы попытаетесь выполнить такую команду, как, например, rm somepath/* , а директория содержит множество файлов с длинными именами, то выполнение может завершиться ошибкой, сообщающей, что список аргументов слишком длинный. Если вы работаете с более старыми версиями Linux или UNIX, в которых могут присутствовать такие ограничения, то будет полезно узнать, как можно использовать xargs таким образом, чтобы обойти их.Вы можете использовать опцию --show-limits для просмотра ограничений, установленных по умолчанию для команды xargs , и опцию -s - для задания максимальной длины выводимых команд. Об остальных опциях вы можете узнать из man-страниц.Использование команды find с опцией -exec или совместно с командой xargs Из руководства "Изучаем Linux, 101: управление файлами и директориями" вы узнали о том, как использовать команду find для поиска файлов на основе их имен, времени модификации, размера и прочих характеристик. Обычно над найденными файлами необходимо выполнять определенные действия - удалять, копировать, переименовывать их и так далее. Сейчас мы рассмотрим опцию -exec команды find , работа которой похожа на работу команды find с последующей передачей вывода команде xargs .Листинг 18. Использование команды find с опцией -exec
Сопоставив результаты листинга 18 с тем, что вам уже известно о xargs , можно обнаружить несколько различий.
find text[12] /xargs cat text3 , чтобы увидеть различия.Теперь давайте вернемся к случаю, когда имя файла содержит пробелы. В листинге 19 мы попытались использовать команду find с опцией -exec вместо команд ls и xargs .Листинг 19. Использование команды find с опцией -exec и файлов, содержащих пробелы в именах
Пока все хорошо. Однако не кажется ли вам, что чего-то здесь не хватает? В каких файлах присутствовали строки, найденные при помощи grep ? Здесь не хватает имен файлов, поскольку find вызывает grep один раз для каждого файла, а grep , будучи умной командой, знает о том, что если ей было передано имя лишь одного файла, то нет необходимости сообщать вам о том, что это был за файл.В этой ситуации мы могли бы воспользоваться командой xargs , однако мы уже знаем о проблеме с файлами, имена которых содержат пробелы. Также мы упоминали тот факт, что команда find может генерировать список имен с пустыми разделителями, благодаря опции -print0 . Современные версии команды find могут разделяться не точкой с запятой, а знаком +, благодаря чему, за один вызов команды find можно передать максимально возможное число имен, так же, как и в случае использования xargs . Излишне говорить о том, что в этом случае вы можете использовать конструкцию {} только один раз, и что она должна являться последним параметром команды. В листинге 20 продемонстрированы оба этих метода.Листинг 20. Использование команд find , xargs и файлов, содержащих пробелы в именах
Оба этих метода являются рабочими и выбор какого-то одного из них часто обусловлен лишь личными предпочтениями пользователя. Помните о том, что передавая по конвейеру объекты с необработанными символами-разделителями и пробелами, вы можете столкнуться с проблемами; поэтому если вы передаете вывод команде xargs , то используйте опцию -print0 команды find , а также опцию -0 команды xargs , которая сообщает, что во входных данных используются пустые разделители. Другие команды, включая tar , также поддерживают опцию -0 и работу с входными данными, содержащими пустые разделители, поэтому всегда следует использовать эту опцию для тех команд, которые ее поддерживают, если только вы уверены на все 100%, что входной список не создаст вам проблем.Наш последний комментарий затрагивает работу со списком файлов. Хорошей идеей будет всегда тщательно проверять ваш список и команды, прежде чем выполнять пакетные операции (например, удаление или переименование множества файлов). Наличие актуальной резервной копии в нужный момент также может оказаться неоценимым. Разделение вывода В завершение этой статьи мы кратко рассмотрим еще одну команду. Иногда может возникнуть необходимость просматривать вывод на экране и одновременно сохранять его в файл. Для этого вы могли бы перенаправить вывод команды в файл в одном окне, а затем с помощью tail -fn1 отслеживать вывод в другом окне, однако проще всего использовать команду tee .Команда tee используется в конвейере, а ее аргументом является имя файла (или имена нескольких файлов), в который будет передаваться стандартный вывод. Опция -a позволяет не замещать старое содержимое файла новым содержимым, а добавлять данные в конец файла. Как уже говорилось при рассмотрении конвейеризации, если вы хотите сохранить как стандартный вывод, так и поток ошибок, то необходимо перенаправлять поток stderr в поток stdout прежде, чем передавать данные на вход команде tee . В листинге 21 приведен пример использования команды tee для сохранения вывода в два файла, f1 и f2.Листинг 21. Разделение потока stdout с помощью команды tee
Symantec и Red Hat расширяют сотрудничество. Oracle представляет модульную ленточную библиотеку StorageTek SL150. Вышло ядро Linux 3.5. Lisp: Слезы радости, часть 2. "Лаборатория Касперского" представляет решение нового поколения для защиты почтовых серверов на базе Linux. Главная » Linux |
© 2024 Team.Furia.Ru.
Частичное копирование материалов разрешено. |