Подсчёт
В европейской культуре очень большим авторитетом пользуются точные числа и количественные оценки. Поэтому пользователю часто бывает любопытно и даже необходимо точно посчитать что-нибудь многочисленное. Компьютер как нельзя более удобен для такой процедуры. Стандартная утилита для подсчёта строк, слов и символов — (от англ. «word count» — «подсчёт слов»). Однако Мефодий запомнил, что в Linux многое можно представить как слова и строки, и решил с её помощью посчитать свои файлы.
$ find . | wc -l 42 $
Пример 10. Подсчёт файлов при помощи и
Удовлетворённый Мефодий получил желаемое число — “”. Для этого ему потребовалась команда — рекомендованный ему Гуревичем инструмент поиска нужных файлов в системе. Мефодий вызвал с одним параметром — каталогом, с которого начинать поиск. выводит список найденных файлов по одному на строку, а поскольку критерии поиска в данном случае не уточнялись, то просто вывела список всех файлов во всех подкаталогах текущего каталога (домашнего каталога Мефодия). Этот список Мефодий передал утилите , попросив её посчитать количество полученных строк “”. выдала в ответ искомое число.
Задав критерии поиска, можно посчитать и что-нибудь менее тривиальное, например, файлы, которые создавались или были изменены в определённый промежуток времени, файлы с определённым режимом доступа, с определённым именем и т. п. Узнать обо всех возможностях поиска при помощи и подсчёта при помощи можно из руководств по этим программам.
Работа на более низком уровне с классом Popen
До сих пор мы изучали функции API высокого уровня в модуле subprocess, особенно . Все они под капотом используют класс . Из-за этого в подавляющем большинстве случаев нам не нужно взаимодействовать с ним напрямую. Однако, когда требуется большая гибкость, без создания объектов не обойтись.
Предположим, например, что мы хотим соединить два процесса, воссоздав поведение конвейера (pipe) оболочки. Как мы знаем, когда передаем две команды в оболочку, стандартный вывод той, что находится слева от пайпа «|», используется как стандартный ввод той, которая находится справа. В приведенном ниже примере результат выполнения двух связанных конвейером команд сохраняется в переменной:
Чтобы воссоздать подобное поведение с помощью модуля subprocess без установки параметра в значение , как мы видели ранее, мы должны напрямую использовать класс :
Копировать
Рассматривая данный пример, вы должны помнить, что процесс, запущенный с использованием класса , не блокирует выполнение скрипта.
Первое, что мы сделали в приведенном выше фрагменте кода, — это создали объект , представляющий процесс . Мы установили этого процесса на . Данное значение указывает, что пайп к указанному потоку должен быть открыт.
Затем мы создали еще один экземпляр класса для процесса
В конструкторе мы, конечно, указали команду и ее аргументы, но вот что важно, мы установили стандартный вывод процесса в качестве стандартного ввода для (), чтобы воссоздать поведение конвейера оболочки
После создания объекта для команды мы закрыли поток процесса , используя метод . Это, как указано в документации, необходимо для того, чтобы первый процесс мог получить сигнал SIGPIPE. Дело в том, что обычно, когда два процесса соединены конвейером, если один справа от «|» ( в нашем примере) завершается раньше, чем тот, что слева (), то последний получает сигнал SIGPIPE (пайп закрыт) и по умолчанию тоже заканчивает свою работу.
Однако при репликации пайплайна между двумя командами в Python возникает проблема. первого процесса открывается как в родительском скрипте, так и в стандартном вводе другого процесса. Таким образом, даже если процесс завершится, пайп останется открытым в вызывающем процессе (нашем скрипте), поэтому никогда не получит сигнал SIGPIPE. Вот почему нам нужно закрыть поток первого процесса в нашем основном скрипте после запуска второго.
Последнее, что мы сделали, — это вызвали метод объекта . Этот метод можно использовать для необязательной передачи данных в процесса. Он ожидает завершения процесса и возвращает кортеж. Где первый элемент — это (на который ссылается переменная ), а второй — процесса.
Смена контекста (context switch)
Само собой, при смене контекста производится много работы. Часть из неё
мы уже описали выше, но особого внимания заслуживает отдельный момент,
который мы ещё не обсуждали.
Кеш процессора
Современные компьютеры много сложнее, чем процессор-шина-память. В частности,
для ускорения работы этой связки был добавлен ещё один вид памяти, который
расположен ближе к процессору, чем RAM — кеш процессора. Размер кеша меньше, чем
памяти. Однако, редко какая программа оперирует всей памятью сразу. Обычно
необходимые для работы программы данные лежат вместе и их размер невелик.
Именно благодаря этому небольшая память кеша, но низкое время обращения
процессора к ней, и даёт значительный прирост производительности на многих
задачах. С другой стороны — при переключении контекстов в кеше может не хватать
места под оперативные данные всех процессов — тогда кеш будет обновляться (также
говорят “прогреваться”) из памяти по мере необходимости. И это может сильно
замедлить работу компьютера по сравнению с работой при горячем кеше.
В следующем примере мы запустим программу в 8 потоков на 8-ми ядрах. Они будут
увеличивать общий счётчик до довольно большого числа. Так как они будут
параллельно обрабатывать одни и те же данные, компьютер будет постоянно
синхронизировать кеши.
Сборка:
Для примера, если запустить эту же программу но на одном ядре (пусть и в 8
потоков) — смены контекста также будут происходить, но кеш будет “горячим” —
программа выполнится быстрее. Для запуска на определённых процессорах программ
(или миграции) используется утилита (или программно
).
Посмотреть же статистическую информацию о смене контекстов за секунду можно всё
также в . Столбик system, раздел “cs” (от “context switch”).
работа с большими файлами
два принципа должны применяться единообразно при работе с большими файлами в Python.
- поскольку любая процедура ввода-вывода может блокировать, мы должны держите каждый этап трубопровода в другом потоке или процесс. В этом примере мы используем потоки, но подпроцессы позволят вам избежать GIL.
- мы должны использовать добавочные читает и пишет так, что мы не ждем перед начинаю прогрессировать.
альтернативой является использование неблокирующего ввода-вывода, хотя это громоздко в стандартный Python. См.gevent для облегченной библиотеки потоков, реализующей синхронный API ввода-вывода с использованием неблокирующих примитивов.
Использование конвейеров
Большинство командлетов PowerShell предназначены для поддержки конвейеров. В большинстве случаев можно передать результаты командлета Get в другой командлет того же существительного.
Например, выходные данные командлета можно передать в командлеты или.
Этот пример конвейера запускает службу WMI на компьютере:
Другой пример: можно передать выходные данные поставщика реестра PowerShell в командлет. В этом примере в раздел реестра MyCompany добавляется новая запись реестра NoOfEmployees со значением 8124.
Многие командлеты служебной программы, такие как,,, и, используются практически исключительно в конвейерах. К этим командлетам можно передать любой тип объекта. В этом примере показано, как сортировать все процессы на компьютере по количеству открытых дескрипторов в каждом процессе.
Объекты можно передавать в командлеты форматирования, экспорта и вывода, такие как,, , и .
В этом примере показано, как использовать командлет для отображения списка свойств объекта процесса.
Кроме того, выходные данные собственных команд можно передать в командлеты PowerShell. Пример:
Важно!
Потоки успехов и ошибок похожи на потоки stdin и stderr других оболочек. Однако stdin не подключен к конвейеру PowerShell для ввода данных. Дополнительные сведения см. в разделе about_Redirection.
С небольшой практикой вы обнаружите, что объединение простых команд в конвейеры экономит время и ввод и делает создание сценариев более эффективным.
Пример
Перенаправление stdout и stderr
Напишем программу main.c:
#include <stdio.h> int main() { fprintf(stdout, "Hello to stdout\n"); fprintf(stderr, "Hello to stderr\n"); return ; }
Далее попробуем перенаправления:
$ gcc main.c $ ./a.out Hello to stdout Hello to stderr $ ./a.out >&2 Hello to stdout Hello to stderr $ (./a.out >&2) 2> err.txt $ cat err.txt Hello to stderr Hello to stdout
Запись данных в файл со стандартного ввода (завершение ввода по Ctrl+D):
$ cat > newfile blah blah
Специальные устройства
$ echo "Hello" > /dev/null $ echo "Hello" > /dev/full bash: echo: write error: No space left on device
Пример с /dev/full не работает на WSL.
Перенаправление разных потоков
Файловый дескриптор (FD) — абстрактный индикатор (дескриптор), используемый для доступа к файлу или другому ресурсу ввода/вывода, например к каналу или сетевому сокету. Файловые дескрипторы являются частью POSIX API. Дескриптор файла является неотрицательным целым числом, обычно представленным на языке программирования C как тип int. Мы это рассмотрим позднее, когда будем программировать на C.
Каждый процесс UNIX (кроме демонов) должен иметь три стандартных файловых дескриптора (0, 1, 2), соответствующих трём стандартным потокам:
- stdin — стандартный ввод
- stdout — стандартный вывод
- stderr — стандартный вывод ошибок
В командной оболочке sh можно указывать номер потока (файловый дескриптор) непосредственно перед символом перенаправления.
К примеру:
команда1 2> файл1
выполняет команду1, направляя стандартный поток ошибок в файл1.
Часто стандартный поток ошибок объединяют со стандартным потоком вывода, чтобы можно было обрабатывать ошибки и обычные результаты работы программы вместе. К примеру:
find / -name .profile > results.txt 2>&1
попытается найти все файлы с именем .profile. Если выполнять эту команду без перенаправлений, она будет направлять результаты поиска в stdout, а сообщения об ошибках (к примеру, о недостаточности прав доступа при попытке поиска в защищённых каталогах) в stderr. По умолчанию обе эти роли выполняет консоль. Если стандартный поток вывода направлен в файл results.txt, то ошибки по-прежнему будут направляться в консоль. Чтобы и ошибки, и результаты поиска направлялись в файл results.txt, стандартные потоки ошибок и вывода были объединены с использованием 2>&1.
Написание 2>&1 перед > не будет работать, так как когда интерпретатор прочитает 2>&1, он ещё не знает, куда перенаправлен стандартный поток вывода, поэтому потоки ошибок и вывода не будут объединены.
Подробное описание
Конвейер — это серия команд, Соединенных операторами конвейера ( ) (ASCII 124). Каждый оператор конвейера отправляет результаты предыдущей команды следующей команде.
Выходные данные первой команды можно отправить для обработки в качестве входных данных во вторую команду. И эти выходные данные можно отправить в еще одну команду. Результатом является сложная цепочка команд или конвейер , состоящая из ряда простых команд.
Например,
В этом примере объекты, порождаемые, отправляются в .
обрабатывает объекты и отправляет их в . обрабатывает объекты и отправляет их по конвейеру. Так как в конвейере больше нет команд, результаты отображаются в консоли.
В конвейере команды обрабатываются в порядке слева направо. Обработка обрабатывается как одна операция, а выходные данные отображаются по мере их создания.
Вот простой пример. следующая команда возвращает Блокнот процесс, а затем останавливает его.
Например,
первая команда использует командлет для получения объекта, представляющего процесс Блокнот. он использует оператор конвейера ( ) для отправки объекта process в командлет, который останавливает процесс Блокнот
Обратите внимание, что у команды нет параметра Name или ID для указания процесса, так как указанный процесс отправляется через конвейер
Этот пример конвейера получает текстовые файлы в текущем каталоге, выбирает только те файлы, которые имеют длину более 10 000 байт, сортирует их по длине и отображает имя и длину каждого файла в таблице.
Этот конвейер состоит из четырех команд в указанном порядке. На следующем рисунке показаны выходные данные каждой команды, которые передаются в следующую команду конвейера.
hashtable
Не все объекты Powershell могут проходить через конвейер. Как написано в документации у всех типов Powershell, кроме hashtable, есть поддержка работы через конвейеры (IEnumerable). При попытке пропустить хэш-таблицу через конвейер возникнет ошибка:
Get-Service : Не удается найти службу с именем службы «System.Collections.Hashtable».
Исправить ее можно несколькими способами. Самый простой — использовать метод ‘GetEnumerator()’. Благодаря этому методу хэш-таблица становится итерируемой и вы сможете использовать индексы и ключи в следующем виде:
Параметр «ErrorAction» нужен т.к. у нас произойдет ошибка из-за ключа ‘State’. Значения хэш таблицы передаются не как целый массив (как в случае с PSCustomObject), а по отдельности. Сначала передается ключ ‘Name’ со значением ‘WinRM’, а затем ‘State’ со значением ‘Restarted’.
Еще два способа получить только ключи или только значения:
Выражения в квадратных скобках и Классы символов
В дополнение к совпадению любого символа в заданной позиции в нашем регулярном выражении, мы также, используя выражения в квадратных скобках, можем задать совпадение единичного символа из указанного набора символов. С выражениями в квадратных скобках мы можем указать набор символов для соответствия (включая символы, которые в противном случае были бы истолкованы как метасимволы). В этом примере, используя набор из двух символов:
grep -h 'zip' dirlist*.txt bzip2 bzip2recover gzip
мы найдём любые строчки, содержащие строки «bzip» или «gzip».
Набор может содержать любое количество символов, а метасимволы теряют своё специальное значение, когда помещаются внутрь квадратных скобок. Тем не менее, есть два случая в которых метасимволы, используемые внутри квадратных скобок, имеют различные значения. Первый – это каретка (^), которая используется для указания отрицания; второй – это тире (-), которое используется для указания диапазона символов.
Отрицание
Если первым символом выражения в квадратных скобках является каретка (^), то остальные символы принимаются как набор символов, которые не должны присутствовать в заданной позиции символа. Сделаем это изменив наш предыдущий пример:
grep -h 'zip' dirlist*.txt bunzip2 gunzip funzip gpg-zip mzip p7zip preunzip prezip prezip-bin unzip unzipsfx
С активированным отрицанием, мы получили список файлов, которые содержат строку «zip», перед которой идёт любой символ, кроме «b» или «g»
Обратите внимание, что zip не был найден. Отрицаемый набор символов всё равно требует символ на заданной позиции, но символ не должен быть членом инвертированного набора.
Символ каретки вызывает отрицание только если он является первым символом внутри выражения в квадратных скобках; в противном случае, он теряет своё специальное назначение и становится обычным символом из набора.
Традиционные диапазоны символов
Если мы хотим сконструировать регулярное выражение, которое должно найти каждый файл из нашего списка, начинающийся на заглавную букву, мы можем сделать следующее:
grep -h '^' dirlist*.txt MAKEDEV GET HEAD POST VBoxClient X X11 Xorg ModemManager NetworkManager VBoxControl VBoxService
Суть в том, что мы разместили все 26 заглавных букв в выражение внутри квадратных скобок. Но мысль печатать их все не вызывает энтузиазма, поэтому есть другой путь:
grep -h '^' dirlist*.txt
Используя трёхсимвольный диапазон, мы можем сократить запись из 26 букв. Таким способом можно выразить любой диапазон символов, включая сразу несколько диапазонов, такие, как это выражение, которое соответствует всем именам файлов, начинающихся с букв и цифр:
grep -h '^' dirlist*.txt
В диапазонах символов мы видим, что символ чёрточки трактуется особым образом, поэтому как мы можем включить символ тире в выражение внутри квадратных скобок? Сделав его первым символом в выражении. Рассмотрим два примера:
grep -h '' dirlist*.txt
Это будет соответствовать каждому имени файла, содержащему заглавную букву. При этом:
grep -h '' dirlist*.txt
будет соответствовать каждому имени файла, содержащему тире, или заглавную «A», или заглавную «Z».
Классы символов POSIX
Подробнее о POSIX вы можете почитать в Википедии.
В POSIX имеются свои классы символов, которые вы можете использовать в регулярных выражениях:
Класс символов | Описание |
---|---|
Алфавитно-цифровые символы. В ASCII эквивалентно: | |
То же самое, что и , с дополнительным символом подчёркивания (_). | |
Алфавитные символы. В ASCII эквивалентно: | |
Включает символы пробела и табуляции. | |
Управляющие коды ASCII. Включает ASCII символы с 0 до 31 и 127. | |
Цифры от нуля до девяти. | |
Видимые символы. В ASCII сюда включены символы с 33 по 126. | |
Буквы в нижнем регистре. | |
Символы пунктуации. В ASCII эквивалентно: [-!»#$%&'()*+,./:;?@_`{|}~] | |
Печатные символы. Все символы в плюс символ пробела. | |
Символы белых пробелов, включающих пробел, табуляцию, возврат каретки, новую строку, вертикальную табуляцию и разрыв страницы. В ASCII эквивалентно: | |
Символы в верхнем регистре. | |
Символы, используемые для выражения шестнадцатеричных чисел. В ASCII эквивалетно: |
В этих выражениях квадратные скобки и двоеточия являются частью записи класса символов (диапазонов).
Внимание: в зависимости от настроек локали, , , и другие буквенные диапазоны могут включать буквы вашего алфавита, например, русского. Т.е
может соответствовать не , а .
Исследование ошибок конвейера
Если PowerShell не может связать переданный объект с параметром командлета получения, команда завершается ошибкой.
В следующем примере мы пытаемся переместить запись реестра из одного раздела реестра в другой. Командлет возвращает путь назначения, который затем передается в командлет. Команда задает текущий путь и имя перемещаемой записи реестра.
Команда завершается ошибкой, и PowerShell выводит следующее сообщение об ошибке:
Для изучения используйте командлет для трассировки компонента привязки параметров PowerShell. В следующем примере выполняется трассировка привязки параметра во время выполнения конвейера. Параметр PSHost отображает результаты трассировки в консоли, а параметр FilePath отправляет результаты трассировки в файл для последующей ссылки.
Результаты трассировки имеют длину, но они показывают значения, привязанные к командлету, а затем именованные значения, привязанные к командлету.
Наконец, он показывает, что попытка привязки пути к параметру назначения не удалась.
Используйте командлет для просмотра атрибутов целевого параметра.
Результаты показывают, что назначение принимает только входные данные конвейера «по имени свойства». Таким образом, объект последовательного объекта должен иметь свойство с именем Destination.
Используйте для просмотра свойств объекта, поступающих из .
Выходные данные показывают, что элемент является объектом Microsoft. Win32. RegistryKey , который не имеет целевого свойства. Это объясняет, почему команда завершилась ошибкой.
Параметр path принимает входные данные конвейера по имени или по значению.
Чтобы исправить эту команду, необходимо указать назначение в командлете и использовать для получения пути к элементу, который нужно переместить.
Например,
Внутреннее продолжение строки
Как уже говорилось, конвейер — это серия команд, Соединенных операторами конвейера ( ), обычно написанными на одной строке. Однако для удобства чтения PowerShell позволяет разбить конвейер на несколько строк.
Если оператор Pipe является последним маркером в строке, средство синтаксического анализа PowerShell присоединяет следующую строку к текущей команде, чтобы продолжить построение конвейера.
Например, следующий однострочный конвейер:
можно записать следующим образом:
Начальные пробелы в последующих строках не являются значимыми. Отступ повышает удобочитаемость.
В PowerShell 7 добавлена поддержка продолжения конвейеров с символом конвейера в начале строки. В следующих примерах показано, как можно использовать эту новую функциональность.
Важно!
При интерактивной работе в оболочке Вставка кода с конвейерами в начале строки выполняется только при использовании клавиши CTRL + V для вставки.
Щелкните правой кнопкой мыши операции вставки, чтобы вставить строки по одному. Поскольку строка не заканчивается символом конвейера, PowerShell считает входные данные полными и выполняет эту строку как введенную.
Замены
Удобство работы с потоком не в последнюю очередь состоит в том, что можно не только выборочно передавать результаты работы программ, но и автоматически заменять один текст другим прямо в потоке.
Для замены одних символов на другие предназначена утилита (сокращение от англ. «translate», «преобразовывать, переводить»), работающая как фильтр. Мефодий решил употребить её прямо по назначению и выполнить при её помощи транслитерацию — замену латинских символов близкими по звучанию русскими.
$ cat cat.info | tr abcdefghijklmnopqrstuvwxyz абцдефгхийклмнопкрстуввсиз \ > | tr ABCDEFGHIJKLMNOPRSTUVWXYZ АБЦДЕФГХИЙКЛМНОПКРСТУВВСИЗ | head -4 Филе: цореутилс.инфо, Ноде: цат инвоцатион, Нест: тац инвоцатион, Тп: Оутпут оф ентире филес `цат': Цонцатенате анд врите филес ================================== $
Пример 14. Замена символов (транслитерация)
Мефодий потрудился, составляя два параметра для утилиты : соответствия латинских букв кириллическим. Первый символ из первого параметра заменяет первым символом второго, второй — вторым и т. д. Мефодий обработал поток фильтром дважды: сначала чтобы заменить строчные буквы, а затем — прописные, он мог бы сделать это и за один проход (просто добавив к параметрам прописные после строчных), но не захотел выписывать столь длинные строки. Полученному на выходе тексту вряд ли можно найти практическое применение, однако транслитерацию можно употребить и с пользой. Если не указать второго параметра, то все символы, перечисленные в первом, будут заменены на «ничто», т. е. попросту удалены из потока. При помощи можно также удалить дублирующиеся символы (например, лишние пробелы или переводы строки), заменить пробелы переводами строк и т. п.
Помимо простой замены отдельных символов, возможна замена последовательностей (слов). Специально для этого предназначен потоковый редактор (сокращение от англ. «stream editor»). Он работает как фильтр и выполняет редактирование поступающих строк: замену одних последовательностей символов на другие, причём можно заменять и регулярные выражения.
Например, Мефодий с помощью может сделать более понятным для непривычного читателя список файлов, выводимый :
$ ls -l | sed s/^-*/Файл:/ | sed s/^d*/Каталог:/ итого 124 Файл: 1 methody methody 2693 Ноя 15 16:09 cat.info Файл: 1 methody methody 69 Ноя 15 16:08 cat.stderr Каталог: 2 methody methody 4096 Ноя 15 12:56 Documents Каталог: 3 methody methody 4096 Ноя 15 13:08 examples Файл: 1 methody methody 83459 Ноя 15 16:11 grep.info Файл: 1 methody methody 26 Ноя 15 13:08 loop Файл: 1 methody methody 23 Ноя 15 13:08 script Файл: 1 methody methody 33 Ноя 15 16:07 textfile Каталог: 2 methody methody 4096 Ноя 15 12:56 tmp Файл: 1 methody methody 32 Ноя 15 13:08 to.sort $
Пример 15. Замена по регулярному выражению
У очень широкие возможности, но довольно непривычный синтаксис, например, замена выполняется командой “”. Чтобы в нём разобраться, нужно обязательно прочесть руководство и знать регулярные выражения.
Стандартный вывод ошибок
В качестве первого примера и упражнения на перенаправление Мефодий решил записать руководство по в свой файл :
$ info cat > cat.info info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. $ head -1 cat.info File: coreutils.info, Node: cat invocation, Next: tac invocation, Up: Output of entire files $
Пример 5. Стандартный вывод ошибок
Удивлённый Мефодий обнаружил, что вопреки его указанию отправляться в файл две строки, выведенные командой , всё равно проникли на терминал. Очевидно, эти строки не попали на стандартный вывод потому, что не относятся непосредственно к руководству, которое должна вывести программа, они информируют пользователя о ходе выполнения работы: записи руководства в файл. Для такого рода диагностических сообщений, а также для сообщений об ошибках, возникших в ходе выполнения программы, в Linux предусмотрен стандартный вывод ошибок (сокращённо — stderr).
- стандартный вывод ошибок
- Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для диагностических сообщений, выводимых процессом.
Использование стандартного вывода ошибок наряду со стандартным выводом позволяет отделить собственно результат работы программы от разнообразной сопровождающей информации, например, направив их в разные файлы. Стандартный вывод ошибок может быть перенаправлен так же, как и стандартный ввод/вывод, для этого используется комбинация символов “”.
$ info cat > cat.info 2> cat.stderr $ cat cat.stderr info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. $
Пример 6. Перенаправление стандартного вывода ошибок
В этот раз на терминал уже ничего не попало, стандартный вывод отправился в файл , стандартный вывод ошибок — в . Вместо “” и “” Мефодий мог бы написать “” и “”. Цифры в данном случае обозначают номера дескрипторов открываемых файлов. Если некая утилита ожидает получить открытый дескриптор с номером, допустим, , то чтобы её запустить обязательно потребуется использовать сочетание “”.
Иногда, однако, требуется объединить стандартный вывод и стандартный вывод ошибок в одном файле, а не разделять их. В командной оболочке для этого имеется специальная последовательность “”. Это означает «направить стандартный вывод ошибок туда же, куда и стандартный вывод»:
$ info cat > cat.info 2>&1 $ head -3 cat.info info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. File: coreutils.info, Node: cat invocation, Next: tac invocation, Up: Output of entire files $
Пример 7. Объединение стандартного вывода и стандартного вывода ошибок
В этом примере важен порядок перенаправлений: в командной строке Мефодий сначала указал, куда перенаправить стандартный вывод (“”) и только потом велел направить туда же стандартный вывод ошибок. Сделай он наоборот (“”), результат получился бы неожиданный: в файл попал бы только стандартный вывод, а диагностические сообщения появились бы на терминале. Однако логика здесь железная: на момент выполнения операции “” стандартный вывод был связан с терминалом, значит, после её выполнения стандартный вывод ошибок тоже будет связан с терминалом. А последующее перенаправление стандартного вывода в файл, конечно, никак не отразится на стандартном выводе ошибок. Номер в конструкции “” — это номер открытого дескриптора. Если бы упомянутая выше утилита, записывающая в четвёртый дескриптор, была написана на shell, в ней бы использовались перенаправления вида “”. Чтобы не набирать громоздкую конструкцию “” в используются сокращения: “” или, что то же самое, “”.
Стандартный вывод
Мефодий уже сталкивался с тем, что некоторые программы умеют выводить не только на терминал, но и в файл, например, при указании параметрического ключа “” с именем файла выведет текст руководства в файл, вместо того, чтобы отображать его на мониторе. Даже если разработчиками программы не предусмотрен такой ключ, Мефодию известен и другой способ сохранить вывод программы в файле вместо того, чтобы выводить его на монитор: поставить знак “” и указать после него имя файла. Таким образом Мефодий уже создавал короткие текстовые файлы (сценарии) при помощи утилиты (см. лекцию Доступ процессов к файлам и каталогам).
$ cat > textfile Это файл для примеров. ^D $ ls -l textfile -rw-r--r-- 1 methody methody 23 Ноя 15 16:06 textfile
Пример 2. Перенаправление стандартного вывода в файл
От использования символа “” возможности самой утилиты , конечно, не расширились. Более того, в этом примере не получила от командной оболочки никаких параметров: ни знака “”, ни последующего имени файла. В этом случае работала как обычно, не зная (и даже не интересуясь!), куда попадут выведенные данные: на экран монитора, в файл или куда-нибудь ещё. Вместо того, чтобы самой обеспечивать доставку вывода до конечного адресата (будь то человек или файл), отправляет все данные на стандартный вывод (сокращённо — stdout).
Подмена стандартного вывода — задача командной оболочки (shell). В данном примере shell создаёт пустой файл, имя которого указано после знака “”, и дескриптор этого файла передаётся программе под номером (стандартный вывод). Делается это очень просто. В лекции Доступ процессов к файлам и каталогам было рассказано о том, как запускаются команды из оболочки. В частности, после выполнения появляется два одинаковых процесса, один из которых — дочерний — должен запустить вместо себя команду (выполнить ). Так вот, перед этим он закрывает стандартный вывод (дескриптор освобождается) и открывает файл (с ним связывается первый свободный дескриптор, т. е. ), а запускаемой команде ничего знать и не надо: её стандартный вывод уже подменён. Эта операция называется перенаправлением стандартного вывода. В том случае, если файл уже существует, shell запишет его заново, полностью уничтожив всё, что в нём содержалось до этого. Поэтому Мефодию, чтобы продолжить записывать данные в , потребуется другая операция — “”.
$ cat >> textfile Пример 1. ^D $ cat textfile Это файл для примеров. Пример 1. $
Пример 3. Недеструктивное перенаправление стандартного вывода
Мефодий получил именно тот результат, который ему требовался: добавил в конец уже существующего файла данные со стандартного вывода очередной команды.
- стандартный вывод
- Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для данных, выводимых процессом.
Перенаправить вывод в файл
Все очень просто. Вы можете перенаправить вывод в файл с помощью символа >. Например, сохраним вывод команды top:
Опция -b заставляет программу работать в не интерактивном пакетном режиме, а n — повторяет операцию пять раз, чтобы получить информацию обо всех процессах. Теперь смотрим что получилось с помощью cat:
Символ «>» перезаписывает информацию из файла, если там уже что-то есть. Для добавления данных в конец используйте «>>». Например, перенаправить вывод в файл linux еще для top:
По умолчанию для перенаправления используется дескриптор файла стандартного вывода. Но вы можете указать это явно. Эта команда даст тот же результат:
Как работает перенаправление ввода вывода
Все команды, которые мы выполняем, возвращают нам три вида данных:
- Результат выполнения команды, обычно текстовые данные, которые запросил пользователь;
- Сообщения об ошибках — информируют о процессе выполнения команды и возникших непредвиденных обстоятельствах;
- Код возврата — число, которое позволяет оценить правильно ли отработала программа.
В Linux все субстанции считаются файлами, в том числе и потоки ввода вывода linux — файлы. В каждом дистрибутиве есть три основных файла потоков, которые могут использовать программы, они определяются оболочкой и идентифицируются по номеру дескриптора файла:
- STDIN или 0 — этот файл связан с клавиатурой и большинство команд получают данные для работы отсюда;
- STDOUT или 1 — это стандартный вывод, сюда программа отправляет все результаты своей работы. Он связан с экраном, или если быть точным, то с терминалом, в котором выполняется программа;
- STDERR или 2 — все сообщения об ошибках выводятся в этот файл.
Перенаправление ввода / вывода позволяет заменить один из этих файлов на свой. Например, вы можете заставить программу читать данные из файла в файловой системе, а не клавиатуры, также можете выводить ошибки в файл, а не на экран и т д. Все это делается с помощью символов «<» и «>».