Linux направить вывод в файл. Текстовые потоки и фильтры

Для того, чтобы записать данные в файл или прочитать их оттуда, процессу необходимо сначала открыть этот файл (при открытии на запись, возможно, придётся предварительно создать его). При этом процесс получает дескриптор (описатель) открытого файла - уникальное для этого процесса число, которое он и будет использовать во всех операциях записи. Первый открытый файл получит дескриптор, второй - 1 и так далее. Закончив работу с файлом, процесс закрывает его, при этом дескриптор освобождается и может быть использован повторно. Если процесс завершается, не закрыв файлы, за него это делает система. Строго говоря, только в операции открытия дескриптора указывается, какой именно файл будет использоваться. В качестве «файла» используются и обычные файлы, и файлы-дырки (чаще всего - терминалы), и каналы , описанные в разделе Pipeline..Конвейер. Дальнейшие операции - чтение, запись и закрытие, работают с дескриптором, как с потоком данных , а куда именно ведёт этот поток, неважно.

Каждый процесс Linux получает при старте три «файла», открытых для него системой. Первый из них (дескриптор) открыт на чтение , это стандартный ввод процесса. Именно со стандартным вводом работают все операции чтения, если в них не указан дескриптор файла. Второй (дескриптор 1) - открыт на запись, это стандартный вывод процесса. С ним работают все операции записи, если дескриптор файла не указан в них явно. Наконец, третий поток данных (дескриптор 2) предназначается для вывода диагностических сообщений, он называется стандартный вывод ошибок . Поскольку эти три дескриптора уже открыты к моменту запуска процесса, первый файл, открытый самим процессом, будет, скорее всего, иметь дескриптор 3 .

Дескриптор Описатель потока данных, открытого процессом. Дескрипторы нумеруются начиная с. При открытии нового потока данных его дескриптор получает наименьший из неиспользуемых в этот момент номеров. Три заранее открытых дескриптора: стандартный ввод (), стандартный вывод (1) и стандартный вывод ошибок (2) процессу выдаются при запуске.

Механизм копирования окружения , описанный в лекции , подразумевает, в числе прочего, копирование всех открытых дескрипторов родительского процесса дочернему. В результате, и родительский, и дочерний процесс имеют под одинаковыми дескрипторами одни и те же потоки данных. Когда запускается стартовый командный интерпретатор , все три заранее открытых дескриптора связаны у него с терминалом (точнее, с соответствующим файлом-дыркой типа tty): пользователь вводит команды с клавиатуры и видит сообщения на экране. Следовательно, любая команда, запускаемая из командной оболочки, будет выводить на тот же терминал, а любая команда, запущенная интерактивно (не в фоне) - вводить оттуда.

Стандартный вывод

Мефодий уже сталкивался с тем, что некоторые программы умеют выводить не только на терминал, но и в файл, например, info при указании параметрического ключа « -o » с именем файла выведет текст руководства в файл, вместо того, чтобы отображать его на мониторе. Даже если разработчиками программы не предусмотрен такой ключ, Мефодию известен и другой способ сохранить вывод программы в файле вместо того, чтобы выводить его на монитор: поставить знак « > » и указать после него имя файла. Таким образом Мефодий уже создавал короткие текстовые файлы (сценарии) при помощи утилиты cat (см. лекцию Доступ процессов к файлам и каталогам).

$ cat > textfile Это файл для примеров. ^D $ ls -l textfile -rw-r--r-- 1 methody methody 23 Ноя 15 16:06 textfile

Пример 2 . Перенаправление стандартного вывода в файл

От использования символа « > » возможности самой утилиты cat , конечно, не расширились. Более того, cat в этом примере не получила от командной оболочки никаких параметров: ни знака « > », ни последующего имени файла. В этом случае cat работала как обычно, не зная (и даже не интересуясь!), куда попадут выведенные данные: на экран монитора, в файл или куда-нибудь ещё. Вместо того, чтобы самой обеспечивать доставку вывода до конечного адресата (будь то человек или файл), cat отправляет все данные на стандартный вывод (сокращённо - stdout).

Подмена стандартного вывода - задача командной оболочки (shell). В данном примере shell создаёт пустой файл, имя которого указано после знака « > », и дескриптор этого файла передаётся программе cat под номером 1 (стандартный вывод ). Делается это очень просто. В лекции Доступ процессов к файлам и каталогам было рассказано о том, как запускаются команды из оболочки. В частности, после выполнения fork() появляется два одинаковых процесса, один из которых - дочерний - должен запустить вместо себя команду (выполнить exec()). Так вот, перед этим он закрывает стандартный вывод (дескриптор 1 освобождается) и открывает файл (с ним связывается первый свободный дескриптор, т. е. 1), а запускаемой команде ничего знать и не надо: её стандартный вывод уже подменён. Эта операция называется перенаправлением стандартного вывода. В том случае, если файл уже существует, shell запишет его заново, полностью уничтожив всё, что в нём содержалось до этого. Поэтому Мефодию, чтобы продолжить записывать данные в textfile , потребуется другая операция - « >> ».

$ cat >> textfile Пример 1. ^D $ cat textfile Это файл для примеров. Пример 1. $

Пример 3 . Недеструктивное перенаправление стандартного вывода

Мефодий получил именно тот результат, который ему требовался: добавил в конец уже существующего файла данные со стандартного вывода очередной команды.

Стандартный вывод Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для данных, выводимых процессом.

Стандартный ввод

Аналогичным образом для передачи данных на вход программе может быть использован стандартный ввод (сокращённо - stdin). При работе с командной строкой стандартный ввод - это символы, вводимые пользователем с клавиатуры. Стандартный ввод можно перенаправить при помощи командной оболочки, подав на него данные из некоторого файла. Символ « < » служит для перенаправления содержимого файла на стандартный ввод программе. Например, если вызвать утилиту sort без параметра, она будет читать строки со стандартного ввода. Команда « sort < имя_файла » подаст на ввод sort данные из файла.

$ sort < textfile Пример 1. Это файл для примеров. $

Пример 4 . Перенаправление стандартного ввода из файла

Результат действия этой команды совершенно аналогичен команде sort textfile , разница в том, что когда используется « < », sort получает данные со стандартного ввода, ничего не зная о файле « textfile », откуда они поступают. Механизм работы shell в данном случае тот же, что и при перенаправлении вывода: shell читает данные из файла « textfile », запускает утилиту sort и передаёт ей на стандартный ввод содержимое файла.

Стоит помнить, что операция « > » деструктивна : она всегда создаёт файл нулевой длины. Поэтому для, допустим, сортировки данных в файле надо применять последовательно sort < файл > новый_файл и mv новый_файл файл . Команда вида команда < файл > тот_же_файл просто урежет его до нулевой длины!

Стандартный ввод Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для ввода данных.

Стандартный вывод ошибок

В качестве первого примера и упражнения на перенаправление Мефодий решил записать руководство по cat в свой файл cat.info:

$ 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 . Стандартный вывод ошибок

Удивлённый Мефодий обнаружил, что вопреки его указанию отправляться в файл две строки, выведенные командой info , всё равно проникли на терминал. Очевидно, эти строки не попали на стандартный вывод потому, что не относятся непосредственно к руководству, которое должна вывести программа, они информируют пользователя о ходе выполнения работы: записи руководства в файл. Для такого рода диагностических сообщений , а также для сообщений об ошибках, возникших в ходе выполнения программы, в Linux предусмотрен стандартный вывод ошибок (сокращённо - stderr).

Стандартный вывод ошибок Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для диагностических сообщений , выводимых процессом.

Использование стандартного вывода ошибок наряду со стандартным выводом позволяет отделить собственно результат работы программы от разнообразной сопровождающей информации, например, направив их в разные файлы. Стандартный вывод ошибок может быть перенаправлен так же, как и стандартный ввод/вывод, для этого используется комбинация символов « 2 ».

$ info cat > cat.info 2> cat.stderr $ cat cat.stderr info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. $

Пример 6 . Перенаправление стандартного вывода ошибок

В этот раз на терминал уже ничего не попало, стандартный вывод отправился в файл cat.info , стандартный вывод ошибок - в cat.stderr . Вместо « > » и « 2 » Мефодий мог бы написать « 1> » и « 2> ». Цифры в данном случае обозначают номера дескрипторов открываемых файлов. Если некая утилита ожидает получить открытый дескриптор с номером, допустим, 4 , то чтобы её запустить обязательно потребуется использовать сочетание « 4> ».

Иногда, однако, требуется объединить стандартный вывод и страндартный вывод ошибок в одном файле, а не разделять их. В командной оболочке bash для этого имеется специальная последовательность « 2>&1 ». Это означает «направить стандартный вывод ошибок туда же, куда и стандартный вывод»:

$ 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 . Объединение стандартного вывода и стандартного вывода ошибок

В этом примере важен порядок перенаправлений: в командной строке Мефодий сначала указал, куда перенаправить стандартный вывод (« > cat.info ») и только потом велел направить туда же стандартный вывод ошибок. Сделай он наоборот (« 2>&1 > cat.info »), результат получился бы неожиданный: в файл попал бы только стандартный вывод, а диагностические сообщения появились бы на терминале. Однако логика здесь железная: на момент выполнения операции « 2>&1 » стандартный вывод был связан с терминалом, значит, после её выполнения стандартный вывод ошибок тоже будет связан с терминалом. А последующее перенаправление стандартного вывода в файл, конечно, никак не отразится на стандартном выводе ошибок. Номер в конструкции « &номер » - это номер открытого дескриптора. Если бы упомянутая выше утилита, записывающая в четвёртый дескриптор, была написана на shell, в ней бы использовались перенаправления вида « >&4 ». Чтобы не набирать громоздкую конструкцию « > файл 2>&1 » в bash используются сокращения: « &> файл » или, что то же самое, « >& файл ».

Перенаправление в никуда

Иногда заведомо известно, что какие-то данные, выведенные программой, не понадобятся. Например, предупреждения со стандартного вывода ошибок. В этом случае можно перенаправить стандартный вывод ошибок в файл-дырку , специально предназначенный для уничтожения данных - /dev/null . Всё, что записывается в этот файл, просто будет выброшено и нигде не сохранится .

$ info cat > cat.info 2> /dev/null $

Пример 8 . Перенаправление в /dev/null

Точно таким же образом можно избавиться и от стандартного вывода, отправив его в /dev/null .

Система ввода/вывода в LINUX .

В системе ввода/вывода все внешние устройства рассматриваются как файлы, над которыми допускается производить обычные файловые операции. Конечно, существуют и драйверы устройств, но интерфейс с ними оформлен для пользователя как обращение к специальному файлу. Специальные файлы являются средством унификации системы ввода/вывода.

Каждому подключенному устройству (терминалу, дискам, принтеру и т. д.), соответствует, как минимум, один специальный файл. Большая часть этих специальных файлов хранится в каталоге /dev:
$ cd /dev
$ ls -l
onsole пульт управления системы
dsk порции на диске
fd0 флоппи-диск 1
mem память
lр принтер
lр0 параллельный порт 0
. . .
root порция на диске для корневой файловой системы
swap своп-порция
syscon альтернативное имя пульта
systty еще одно имя для системной консоли
term директория для терминалов
ttyS0 серийный порт 0 (COM1)
. . .

Когда программа выполняет запись в такой специальный файл, то ОС система перехватывает их и направляет на устройство, например принтер). При чтении данных из такого типа файла в действительности они принимаются с устройства, например, с диска. Программа не должна учитывать особенности работы устройства ввода/вывода. Для этой цели и служат специальные файлы (драйверы), которые выполняют функции интерфейса между компонентами ядра ОС и прикладными программами общего назначения.

Система обнаруживает отличие обычного файла от специального только после того, как будет проанализирован соответствующий индексный дескриптор, на который ссылается запись в каталоге.
Индексный дескриптор специального файла содержит информацию о классе устройства, его типе и номере. Класс устройства определяет устройства с посимвольным обменом и с поблочным обменом. Примером устройства с посимвольным обменом может служить клавиатура. Специальные файлы, обеспечивающие связь с устройствами такого типа, называют байт-ориентированными. Для блочных устройств характерен обмен большими блоками информации, это ускоряет обмен и делает его более эффективным. Все дисковые устройства поддерживают блочный обмен, а специальные файлы, обслуживающие их, называют блок-ориентированными. Специальные файлы не содержат какой-либо символьной информации, поэтому в листинге каталога их длина не указывается.

Тип и номер устройства, также являются основными характеристиками специальных файлов (в поле длины помещаются главный и дополнительный номера соответствующего устройства). Первый из них определяет тип устройства, второй - идентифицирует его среди однотипных устройств. ОС может одновременно обслуживать несколько десятков, и даже сотни терминалов. Каждый из них должен иметь свой собственный специальный файл, поэтому наличие главного и дополнительного номеров позволяет установить требуемое соответствие между устройством и таким файлом.

На одном диске можно создать несколько файловых систем. Некоторые системы используют по одной файловой системе на диске, а другие - по несколько. Новую файловую систему можно создать с помощью команды mkfs (make file system). Например, выражение # /sbin/mkfs /dev/dsk/fl1 512 означает: создать на флоппи-диске b: размером в 512 блоков.

По желанию можно задать размер файловой системы в блоках и количество i-узлов (т. е. максимальное число файлов, которые могут быть сохранены в файловой системе). По умолчанию число i-узлов равно числу блоков, деленному на четыре. Максимальное число i-узлов в одной файловой системе 65 000. Если по некоторым причинам вам необходимо более 65000 i-узлов на диске, необходимо создать две или более файловые системы на этом диске.

Всякая файловая система может быть прикреплена (монтирована) к общему дереву каталогов, в любой его точке. Например, каталог / - это корневой (root) каталог системы, кроме этого, он является основанием файловой системы, которая всегда монтирована. Каталог /usr1 находится в каталоге /, но в данном случае является отдельной файловой системой от корневой файловой системы, так как все файлы в нем находятся на отдельной части диска или вообще на отдельном диске. Файловая система /usr1 - монтируемая файловая система - корень в точке, где каталог /usr1 существует в общей иерархии (рис. 1 и 2).

Рис. 1. Файловая система перед
монтированием /dev/dsk/os1

Рис. 2. Файловая система после
монтирования /dev/dsk/os1 как /usr/

Для монтирования файловой системы используется команда /sbin/mount. Эта команда разрешает расположить данную файловую систему везде в существующей структуре каталогов:
#/sbin/mount/dev/dsk/osl/usr1 монтирует /dev/dsk/osl на /usr1
#/sbin/mount/dev/dsk/flt/а монтирует /dev/dsk/flt на /а

Если нужно монтировать файловую систему на диски, которые должны быть защищены от записи, чтобы система была доступна только для чтения, необходимо добавить опцию - r к команде /sbin/mount.
Каталог, к которому прикрепляется монтируемая файловая система, должен быть в данный момент пустой, так как содержимое его будет недоступно, пока файловая система монтируется.

Чтобы получить информацию о файловых системах, которые смонтированы, например, на системе LINUX, можно использовать команду /sbin/mount без аргументов (рис. 3).

Рис. 3.

Эта команда выводит каталог, на который была смонтирована файловая система (например, usrl), устройство /dev, на котором она находится, час и дата, когда она была смонтирована. Для демонтирования файловой системы используется команда /sbin/umount, которая имеет обратное действие по отношению к команде mount. Она освобождает файловую систему и как бы вынимает ее целиком из структуры каталогов, так что все ее собственные файлы и каталоги становятся недоступны:
# /sbin/umount /b
# /sbin/umount /dev/dsk/0s2

Корневая файловая система не может быть демонтирована. Кроме того, команда umount не будет выполнена, если кто-нибудь использует файл из той файловой системы, которую пытаются демонтировать (это может быть даже простое пребывание пользователя в одном из каталогов демонтируемой файловой системы).

В командах mount и umount пользователь использует аббревиатуру физических дисковых устройств.
В LINUX дисковые устройства имеют своеобразные обозначения. В LINUX пользователь никогда не сталкивается с проблемой точного указания физического устройства, на котором располагается информация. В LINUX произвольное число внешних устройств может быть очень большим, поэтому, пользователь имеет дело только с именем каталога, в котором находятся нужные ему файлы. Все файловые системы монтируются один раз, как правило, при загрузке системы. На некоторые каталоги могут быть смонтированы файловые системы и с удаленных компьютеров.

Для физических устройств в LINUX существуют директории dsk и rdsk, которые содержат файлы, соответствующие дисковым устройствам. Обыкновенно имена файлов в этих директориях одинаковы и единственная разница между ними, что директория rdsk содержит дисковые устройства со специальным доступом (raw), который используют некоторые устройства системы для более быстрого доступа к диску. Одна типичная директория dsk содержит следующие устройства:
$ 1s /dev/dsk
0s0 1s0 c0t0d0s0 c0tld0s0 f0 f05q f13dt fld8d
0sl 1sl c0t0d0sl c0tld0sl f03d f05qt f13h fld8dt
0s2 1s2 c0t0d0s2 c0tld0s2 f03dt f0d8d f13ht fld8t
. . .
$

B системе LINUX дисковые устройства логически разделены на секции, подобно разделам определяемым в Partition Table MasterBoot MS DOS. Файлы 0s1, 0s2, 0s3 и т. д, соответствуют секциям первой, второй, третьей и т. д. диска с номером 0. Файлы 1s0, 1sl, 1s2 и т. д. соответствуют секциям первой, второй, третьей и т. д. диска с номером 1. Если система имеет больше дисков, секции будут пронумерованы ns0, nsl и т. д. для каждого диска с номером n.

Системы с большим количеством дисковых устройств используют следующую систему нумерации:
с controller d disk s section

где controller - номер контроллера диска; disk - номер диска; section -номер секции диска.
Так, 0s0 обычно эквивалентно c0t0d0s0, а 0sl - c0t0d0sl, и трехсимвольные имена секций - это просто сокращение для дискового контроллера с номером 0.

Файлы, имена которых начинаются с f, определяют различные виды гибких дисков. Каталог rmt содержит файлы на устройствах типа магнитная лента:
$ 1s /dev/rmt
c0s0 cls0 c3s0 ntape ntapel tape tapel

Файлы c0s0, cls0, c2s0 и c3s0 определяют четыре кассетных ленточных запоминающих устройства. Файлы tape и tapel определяют магнитные запоминающие устройства с двумя бобинами. Файлы, чьи имена начинаются с n, относятся к тем же устройствам, только лента не перематывается после использования, в то время как использование других файлов заставляет ленту перематываться, когда использующая ее программа заканчивает работу.

В некоторых системах эти файлы имеют другие названия, однако все они всегда находятся в /dev и словарь, который обычно приходит с системой, содержит подробное описание устройств и связанных с ними файлов.

Файловая система extX при операциях ввода/вывода использует буферизацию данных. При считывании блока информации ядро выдает запрос операции ввода/вывода на несколько расположенных рядом блоков. Такие операции сильно ускоряют извлечение данных при последовательном считывании файлов. При занесении данных в файл файловая система extX, записывая новый блок, заранее размещает рядом до 8 смежных блоков. Такой метод позволяет размещать файлы в смежных блоках, что ускоряет их чтение и дает возможность достичь высокой производительности системы.

Встроенные возможности перенаправления в Linux предоставляют вам широкий набор инструментов, используемых упрощения для всех видов задач. Умение управлять различными потоками ввода-вывода в значительно увеличит производительность, как при разработке сложного программного обеспечения, так и при управлении файлами с помощью командной строки.

Потоки ввода-вывода

Ввод и вывод в окружении Linux распределяется между тремя потоками:

  • Стандартный ввод (standard input, stdin, поток номер 0)
  • Стандартный вывод (standard output, stdout, номер 1)
  • Стандартная ошибка, или поток диагностики (standard error, stderr, номер 2)

При взаимодействии пользователя с терминалом стандартный ввод передается через клавиатуру пользователя. Стандартный вывод и стандартная ошибка отображаются на терминале пользователя в виде текста. Все эти три потока называются стандартными потоками.

Стандартный ввод

Стандартный входной поток обычно передаёт данные от пользователя к программе. Программы, которые предполагают стандартный ввод, обычно получают входные данные от устройства (например, клавиатуры). Стандартный ввод прекращается по достижении EOF (end-of-file, конец файла). EOF указывает на то, что больше данных для чтения нет.

Чтобы увидеть, как работает стандартный ввод, запустите программу cat. Название этого инструмента означает «concatenate» (связать или объединить что-либо). Обычно этот инструмент используется для объединения содержимого двух файлов. При запуске без аргументов cat открывает командную строку и принимает содержание стандартного ввода.

Теперь введите несколько цифр:

1
2
3
ctrl-d

Вводя цифру и нажимая enter, вы отправляете стандартный ввод запущенной программе cat, которая принимает эти данные. В свою очередь, программа cat отображает полученный ввод в стандартном выводе.

Пользователь может задать EOF, нажав ctrl-d, после чего программа cat остановится.

Стандартный вывод

Стандартный вывод записывает данные, сгенерированные программой. Если стандартный выходной поток не был перенаправлен, он выведет текст в терминал. Попробуйте запустить следующую команду для примера:

echo Sent to the terminal through standard output

Команда echo без дополнительных опций отображает на экране все аргументы, переданные ей в командной строке.

Теперь запустите echo без аргументов:

Команда вернёт пустую строку.

Стандартная ошибка

Этот стандартный поток записывает ошибки, создаваемые программой, которая вышла из строя. Как и стандартный вывод, этот поток отправляет данные в терминал.

Рассмотрим пример потока ошибок команды ls. Команда ls отображает содержимое каталогов.

Без аргументов эта команда возвращает содержимое текущего каталога. Если указать в качестве аргумента ls имя каталога, команда вернёт его содержимое.

Поскольку каталога % не существует, команда вернёт стандартную ошибку:

ls: cannot access %: No such file or directory

Перенаправление потоков

Linux предоставляет специальные команды для перенаправления каждого потока. Эти команды записывают стандартный вывод в файл. Если вывод перенаправлен в несуществующий файл, команда создаст новый файл с таким именем и сохранит в него перенаправленный вывод.

Команды с одной угловой скобкой переписывают существующий контент целевого файла:

  • > — стандартный вывод
  • < — стандартный ввод
  • 2> — стандартная ошибка

Команды с двойными угловыми скобками не переписывают содержимое целевого файла:

  • >> — стандартный вывод
  • << — стандартный ввод
  • 2>> — стандартная ошибка

Рассмотрим следующий пример:

cat > write_to_me.txt
a
b
c
ctrl-d

В данном примере команда cat используется для записи выходных данных в файл.

Просмотрите содержимое write_to_me.txt:

cat write_to_me.txt

Команда должна вернуть:

Снова перенаправьте cat в файл write_to_me.txt и введите три цифры.

cat > write_to_me.txt
1
2
3
ctrl-d

Теперь проверьте содержимое файла.

cat write_to_me.txt

Команда должна вернуть:

Как видите, файл содержит только последние выходные данные, поскольку в команде, перенаправляющей выход, использовалась одна угловая скобка.

Теперь попробуйте запустить ту же команду с двумя угловыми скобками:

cat >> write_to_me.txt
a
b
c
ctrl-d

Откройте write_to_me.txt:

1
2
3
a
b
c

Команды с двойными угловыми скобками не перезаписывают существующий контент, а дополняют его.

Конвейеры

Конвейеры (pipes) перенаправляют потоки вывода одной команды на вход другой. При этом данные, передаваемые второй программе, не отображаются в терминале. На экране данные появятся только после обработки второй программой.

Конвейеры в Linux представлены вертикальной чертой.

Например:

Такая команда передаст вывод ls (содержимое текущего каталога) программе less, которая отображает передаваемые ей данные построчно. Как правило, ls выводит содержимое каталогов подряд, не разбивая на строки. Если перенаправить вывод ls в less, то последняя команда разделит вывод на строки.

Как видите, конвейер может перенаправить вывод одной команды на вход другой, в отличие от > и >>, которые перенаправляют данные только в файлы.

Фильтры

Фильтры – это команды, которые могут изменить перенаправление и вывод конвейера.

Примечание : Фильтры также являются стандартными командами Linux, которые можно использовать и без конвейера.

  • find – выполняет поиск файла по имени.
  • grep – выполняет поиск текста по заданному шаблону.
  • tee – перенаправляет стандартный ввод в стандартный вывод и один или несколько файлов.
  • tr – поиск и замена строк.
  • wc – подсчёт символов, строк и слов.

Примеры перенаправления ввода-вывода

Теперь, когда вы ознакомились с основными понятиями и механизмами перенаправления, рассмотрим несколько базовых примеров их использования.

команда > файл

Такой шаблон перенаправляет стандартный вывод команды в файл.

ls ~ > root_dir_contents.txt

Эта команда передает содержимое root каталога системы в качестве стандартного вывода и записывает вывод в файл root_dir_contents. Это удалит все предыдущее содержимое в файле, так как в команде использована одна угловая скобка.

команда > /dev/null

/dev/null – это специальный файл (так называемое «пустое устройство»), который используется для подавления стандартного потока вывода или диагностики, чтобы избежать нежелательного вывода в консоль. Все данные, попадающие в /dev/null, сбрасываются. Перенаправление в /dev/null обычно используется в сценариях оболочки.

ls > /dev/null

Такая команда сбрасывает стандартный выходной поток, возвращаемый командой ls, передав его в /dev/null.

команда 2 > файл

Этот шаблон перенаправляет стандартный поток ошибок команды в файл, перезаписывая его текущее содержимое.

mkdir "" 2> mkdir_log.txt

Эта команда перенаправит ошибку, вызванную неверным именем каталога, и запишет её в log.txt. Обратите внимание: ошибка по-прежнему отображается в терминале.

команда >> файл

Этот шаблон перенаправляет стандартный выход команды в файл, не переписывая текущего содержимого файла.

echo Written to a new file > data.txt
echo Appended to an existing file"s contents >> data.txt

Эта пара команд сначала перенаправляет вводимый пользователем текст в новый файл, а затем вставляет его в существующий файл, не переписывая его содержимого.

команда 2>>файл

Этот шаблон перенаправляет стандартный поток ошибок команды в файл, не перезаписывая существующего содержимого файла. Он подходит для создания логов ошибок программы или сервиса, поскольку содержимое лога не будет постоянно обновляться.

find "" 2> stderr_log.txt
wc "" 2>> stderr_log.txt

Приведенная выше команда перенаправляет сообщение об ошибке, вызванное неверным аргументом find, в файл stderr_log.txt, а затем добавляет в него сообщение об ошибке, вызванной недействительным аргументом wc.

команда | команда

Этот шаблон перенаправляет стандартный выход первой команды на стандартный вход второй команды.

find /var lib | grep deb

Эта команда ищет в каталоге /var и его подкаталогах имена файлов и расширения deb и возвращает пути к файлам, выделяя шаблон поиска красным цветом.

команда | tee файл

Такой шаблон перенаправляет стандартный вывод команды в файл и переписывает его содержимое, а затем отображает перенаправленный выход в терминале. Если указанного файла не существует, он создает новый файл.

В данном шаблоне команда tee, как правило, используется для просмотра вывода программы и одновременного сохранения его в файл.

wc /etc/magic | tee magic_count.txt

Такая команда передаёт количество символов, строк и слов в файле magic (Linux использует его для определения типов файлов) команде tee, которая отправляет эти данные в терминал и в файл magic_count.txt.

команда | команда | команда >> файл

Этот шаблон перенаправляет стандартный вывод первой команды и фильтрует ее через следующие две команды, а затем добавляет окончательный результат в файл.

ls ~ | grep *tar | tr e E >> ls_log.txt

Такая команда отправляет вывод ls для каталога root команде grep. В свою очередь, grep ищет в полученных данных файлы tar. После этого результат grep передаётся команде tr, которая заменит все символы е символом Е. Полученный результат будет добавлен в файл ls_log.txt (если такого файла не существует, команда создаст его автоматически).

Заключение

Функции перенаправления ввода-вывода в Linux сначала кажутся слишком сложными. Однако работа с перенаправлением – один из важнейших навыков системного администратора.

Чтобы узнать больше о какой-либо команде, используйте:

man command | less

Например:

Такая команда вернёт полный список команд для tee.

Tags:
  • Перевод

Если вы уже освоились с основами терминала, возможно, вы уже готовы к тому, чтобы комбинировать изученные команды. Иногда выполнения команд оболочки по одной вполне достаточно для решения некоей задачи, но в некоторых случаях вводить команду за командой слишком утомительно и нерационально. В подобной ситуации нам пригодятся некоторые особые символы, вроде угловых скобок.

Для оболочки, интерпретатора команд Linux, эти дополнительные символы - не пустая трата места на экране. Они - мощные команды, которые могут связывать воедино различные фрагменты информации, разделять то, что было до этого цельным, и делать ещё много всего. Одна из самых простых, и, в то же время, мощных и широко используемых возможностей оболочки - это перенаправление стандартных потоков ввода/вывода.

Три стандартных потока ввода/вывода

Для того, чтобы понять то, о чём мы будем тут говорить, важно знать, откуда берутся данные, которые можно перенаправлять, и куда они идут. В Linux существует три стандартных потока ввода/вывода данных.

Первый - это стандартный поток ввода (standard input). В системе это - поток №0 (так как в компьютерах счёт обычно начинается с нуля). Номера потоков ещё называют дескрипторами. Этот поток представляет собой некую информацию, передаваемую в терминал, в частности - инструкции, переданные в оболочку для выполнения. Обычно данные в этот поток попадают в ходе ввода их пользователем с клавиатуры.

Второй поток - это стандартный поток вывода (standard output), ему присвоен номер 1. Это поток данных, которые оболочка выводит после выполнения каких-то действий. Обычно эти данные попадают в то же окно терминала, где была введена команда, вызвавшая их появление.

И, наконец, третий поток - это стандартный поток ошибок (standard error), он имеет дескриптор 2. Этот поток похож на стандартный поток вывода, так как обычно то, что в него попадает, оказывается на экране терминала. Однако, он, по своей сути, отличается от стандартного вывода, как результат, этими потоками, при желании, можно управлять раздельно. Это полезно, например, в следующей ситуации. Есть команда, которая обрабатывает большой объём данных, выполняя сложную и подверженную ошибкам операцию. Нужно, чтобы полезные данные, которые генерирует эта команда, не смешивались с сообщениями об ошибках. Реализуется это благодаря раздельному перенаправлению потоков вывода и ошибок.

Как вы, вероятно, уже догадались, перенаправление ввода/вывода означает работу с вышеописанными потоками и перенаправление данных туда, куда нужно программисту. Делается это с использованием символов > и < в различных комбинациях, применение которых зависит от того, куда, в итоге, должны попасть перенаправляемые данные.

Перенаправление стандартного потока вывода

Предположим, вы хотите создать файл, в который будут записаны текущие дата и время. Дело упрощает то, что имеется команда, удачно названная date , которая возвращает то, что нам нужно. Обычно команды выводят данные в стандартный поток вывода. Для того, чтобы эти данные оказались в файле, нужно добавить символ > после команды, перед именем целевого файла. До и после > надо поставить пробел.

При использовании перенаправления любой файл, указанный после > будет перезаписан. Если в файле нет ничего ценного и его содержимое можно потерять, в нашей конструкции допустимо использовать уже существующий файл. Обычно же лучше использовать в подобном случае имя файла, которого пока не существует. Этот файл будет создан после выполнения команды. Назовём его date.txt . Расширение файла после точки обычно особой роли не играет, но расширения помогают поддерживать порядок. Итак, вот наша команда:

$ date > date.txt
Нельзя сказать, что сама по себе эта команда невероятно полезна, однако, основываясь на ней, мы уже можем сделать что-то более интересное. Скажем, вы хотите узнать, как меняются маршруты вашего трафика, идущего через интернет к некоей конечной точке, ежедневно записывая соответствующие данные. В решении этой задачи поможет команда traceroute , которая сообщает подробности о маршруте трафика между нашим компьютером и конечной точкой, задаваемой при вызове команды в виде URL. Данные включают в себя сведения обо всех маршрутизаторах, через которые проходит трафик.

Так как файл с датой у нас уже есть, будет вполне оправдано просто присоединить к этому файлу данные, полученные от traceroute . Для того, чтобы это сделать, надо использовать два символа > , поставленные один за другим. В результате новая команда, перенаправляющая вывод в файл, но не перезаписывающая его, а добавляющая новые данные после старых, будет выглядеть так:

$ traceroute google.com >> date.txt
Теперь нам осталось лишь изменить имя файла на что-нибудь более осмысленное, используя команду mv , которой, в качестве первого аргумента, передаётся исходное имя файла, а в качестве второго - новое:

$ mv date.txt trace1.txt

Перенаправление стандартного потока ввода

Используя знак < вместо > мы можем перенаправить стандартный ввод, заменив его содержимым файла.

Предположим, имеется два файла: list1.txt и list2.txt , каждый из которых содержит неотсортированный список строк. В каждом из списков имеются уникальные для него элементы, но некоторые из элементов список совпадают. Мы можем найти строки, которые имеются и в первом, и во втором списках, применив команду comm , но прежде чем её использовать, списки надо отсортировать.

Существует команда sort , которая возвращает отсортированный список в терминал, не сохраняя отсортированные данные в файл, из которого они были взяты. Можно отправить отсортированную версию каждого списка в новый файл, используя команду > , а затем воспользоваться командой comm . Однако, такой подход потребует как минимум двух команд, хотя то же самое можно сделать в одной строке, не создавая при этом ненужных файлов.

Итак, мы можем воспользоваться командой < для перенаправления отсортированной версии каждого файла команде comm . Вот что у нас получилось:

$ comm <(sort list1.txt) <(sort list2.txt)
Круглые скобки тут имеют тот же смысл, что и в математике. Оболочка сначала обрабатывает команды в скобках, а затем всё остальное. В нашем примере сначала производится сортировка строк из файлов, а потом то, что получилось, передаётся команде comm , которая затем выводит результат сравнения списков.

Перенаправление стандартного потока ошибок

И, наконец, поговорим о перенаправлении стандартного потока ошибок. Это может понадобиться, например, для создания лог-файлов с ошибками или объединения в одном файле сообщений об ошибках и возвращённых некоей командой данных.

Например, что если надо провести поиск во всей системе сведений о беспроводных интерфейсах, которые доступны пользователям, у которых нет прав суперпользователя? Для того, чтобы это сделать, можно воспользоваться мощной командой find .

Обычно, когда обычный пользователь запускает команду find по всей системе, она выводит в терминал и полезные данные и ошибки. При этом, последних обычно больше, чем первых, что усложняет нахождение в выводе команды того, что нужно. Решить эту проблему довольно просто: достаточно перенаправить стандартный поток ошибок в файл, используя команду 2> (напомним, 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, 101

Текстовые потоки и фильтры

Обработка текста в командной строке с использованием текстовых утилит GNU

Серия контента:

Краткий обзор

В этой статье вы познакомитесь с фильтрами , которые позволяют строить сложные конвейеры для манипуляций с текстом. Вы узнаете, как выводить текст, сортировать его, выполнять подсчет слов и строк, преобразовывать символы, а также о многом другом. Также вы научитесь работать с потоковым редактором sed .

В этой статье будут рассмотрены следующие темы:

Об этой серии

Эта серия статей поможет вам освоить задачи администрирования операционной системы Linux. Вы также можете использовать материал этих статей для подготовки к .

Чтобы посмотреть описания статей этой серии и получить ссылки на них, обратитесь к нашему . Этот перечень постоянно дополняется новыми статьями по мере их готовности и содержит самые последние (по состоянию на апрель 2009 года) цели экзаменов сертификации LPIC-1. Если какая-либо статья отсутствует в перечне, можно найти ее более раннюю версию, соответствующую предыдущим целям LPIC-1 (до апреля 2009 года), обратившись к нашим .

  • Обработка текстовых файлов и потоков вывода текстовыми фильтрами для модификации вывода.
  • Использование стандартных команд UNIX из состава пакета GNU textutils.
  • Использование редактора sed для создания сценариев, состоящих из сложных последовательностей действий над текстовыми файлами.

Эта статья поможет вам подготовиться к сдаче экзамена LPI 101 на администратора начального уровня (LPIC-1) и содержит материалы цели 103.2 темы 103. Цель имеет вес 3. Материал этой статьи соответствует целям экзамена LPI 101 по состоянию на апрель 2009 года. Всегда обращайтесь к Web-сайту программы сертификации LPIC, чтобы уточнить последние цели.

Необходимые условия

Чтобы извлечь наибольшую пользу из наших статей, необходимо обладать базовыми знаниями о Linux и иметь работоспособный компьютер с Linux, на котором можно будет выполнять все встречающиеся команды. Иногда различные версии программ выводят результаты по-разному, поэтому содержимое листингов и рисунков может отличаться от того, что вы увидите на вашем компьютере.

Фильтрация текста

Как связаться с Яном

Ян – один из наших наиболее популярных и плодовитых авторов. Ознакомьтесь со (EN), опубликованными на сайте developerWorks. Вы можете найти контактные данные в и связаться с ним, а также с другими авторами и участниками ресурса My developerWorks.

Фильтрация текста – это процесс получения входного текстового потока, выполнения неких преобразований над ним и передача измененных данных в выходной поток. Хотя входные или выходные данные могут поступать из файлов, в UNIX® и Linux фильтрация обычно осуществляется путем составления конвейеров из команд, в которых вывод одной команды передается по программному каналу (или перенаправляется ) на вход следующей команде. Более подробно программные каналы и перенаправления рассматриваются в статье "Потоки, программные каналы и перенаправления " (см. ), а сейчас давайте рассмотрим программные каналы и простые перенаправления вывода с помощью операторов | и >.

Потоки

Поток – это всего лишь последовательность байтов, которые могут быть считаны или записаны с помощью библиотечных функций, скрывающих подробности реализации и работы устройств от приложений. Одна и та же программа может считывать или отправлять данные на терминал, в файл или сетевое местоположение с помощью потоков независимо от используемого устройства. В современных средах программирования и командных интерпретаторах используются три стандартных потока:

  • stdin стандартный поток ввода (standard input stream), обеспечивающий ввод для команд.
  • stdout стандартный поток вывода (standard output stream), обеспечивающий отображение результатов выполнения команд.
  • stderr стандартный поток ошибок (standard error stream), обеспечивающий отображение ошибок, возникающих при выполнении команд.

Конвейеризация с использованием оператора |

Передаваемые командам параметры могут служить входными данными этих команд, а выходные данные могут выводиться на ваш терминал. Многие команды обработки текста (фильтры) могут получать входные данные либо из стандартного потока ввода, либо из файла. Чтобы передать вывод команды1 на вход команде2 (выступающей в качестве фильтра), необходимо соединить эти две команды оператором конвейеризации ввода/вывода (|). В листинге 1 показано, как перенаправить вывод команды echo на вход команде sort , которая сортирует полученный список слов.

Листинг 1. Передача вывода команды echo на вход команды sort
$ echo -e "apple\npear\nbanana"|sort apple banana pear

У любой из этих команд могут иметься опции или аргументы. С помощью оператора | можно также перенаправить вывод второй команды на вход третьей команде и так далее. Построение длинных конвейеров из команд, каждая из которых имеет свой ограниченный функционал – это распространенный в Linux и UNIX прием, используемый для решения поставленных задач. Иногда аргументом команды может являться не имя файла, а знак дефиса (-); это означает, что входные данные следует принимать со стандартного устройства ввода, а не из файла.

Перенаправление вывода с помощью оператора >

Конечно, хорошо иметь возможность создавать конвейеры из нескольких команд и выводить результаты на экран терминала, однако иногда возникает необходимость сохранить вывод в файл. Для этого используется оператор перенаправления вывода (>).

В оставшихся примерах этой статьи мы будем использовать небольшие файлы, поэтому давайте создадим директорию с именем lpi103-2 и перейдем в нее. После этого давайте перенаправим с помощью оператора > вывод команды echo в файл с именем text1. Эти действия показаны в листинге 2. Заметьте, что поскольку весь вывод перенаправляется в файл, он не отображается на экране.

Листинг 2. Перенаправление вывода команды в файл
$ mkdir lpi103-2 $ cd lpi103-2 $ echo -e "1 apple\n2 pear\n3 banana" > text1

Теперь, когда у нас имеется несколько инструментов для конвейеризации и перенаправления, давайте рассмотрим несколько распространенных в Linux и UNIX команд обработки текста и фильтров. В этом разделе вы познакомитесь с некоторыми основными командами; для получения дополнительной информации о них обращайтесь к соответствующим man-страницам.

Команды cat, od и split

После того, как вы создали файл test1, вы можете просмотреть его содержимое. Для вывода содержимого файла на стандартное устройство вывода используется команда cat (сокращенно от concatenate – объединять). В листинге 3 на экран выводится содержимое только что созданного нами файла.

Листинг 3. Вывод содержимого файла с помощью команды cat
$ cat text1 1 apple 2 pear 3 banana

Если не указать имя файла (или поставить вместо имени файла дефис), то команда cat принимает входные данные со стандартного устройства ввода. Давайте используем эту возможность (а также перенаправление вывода) для создания еще одного текстового файла, как показано в листинге 4.

Листинг 4. Создание текстового файла с помощью команды cat
$ cat >text2 9 plum 3 banana 10 apple
Другие простые фильтры

Другим примером простого фильтра является команда tac (перевернутое имя команды cat). Эта команда выполняет действие команды cat наоборот – строки файла выводятся в обратном порядке. Попробуйте самостоятельно выполнить следующую команду:
tac text2 text1

В листинге 4 команда cat продолжает считывать данные с устройства stdin до тех пор, пока не будет достигнут конец файла. Чтобы обозначить конец файла, нажмите комбинацию клавиш Ctrl-d (удерживайте Ctrl и нажмите d ). Эта же комбинация клавиш используется для выхода из командного интерпретатора bash. Используйте клавишу табуляции, чтобы выстроить названия фруктов в столбец.

Вы еще не забыли, что cat – это сокращение от concatenate ? С помощью cat вы можете объединить несколько файлов и вывести их содержимое на экран. В листинге 5 показано содержимое двух файлов, которые мы создали.

Листинг 5. Объединение двух файлов с помощью команды cat
$ cat text* 1 apple 2 pear 3 banana 9 plum 3 banana 10 apple

Обратите внимание на различное выравнивание содержимого двух текстовых файлов при выводе их на экран с помощью cat . Чтобы разобраться, почему это происходит, необходимо посмотреть на управляющие символы, которые присутствуют в файлах. Эти символы влияют на вывод текста, но не имеют визуального отображения, поэтому необходимо создать дамп файла в формате, позволяющем увидеть и определить эти специальные символы. Для этих целей предназначена GNU-утилита od (O ctal D ump).

Команда od имеет несколько опций; например, опция -A управляет основанием смещения файлов, а опция -t – формой выводимого содержимого. Основание может быть указано как o (восьмеричное, используется по умолчанию), d (десятичное), x (шестнадцатеричное) или n (смещения не отображаются). Вы можете выводить содержимое в виде восьмеричных, шестнадцатеричных, десятичных значений, значений с плавающей точкой, ASCII-символов с escape-последовательностями или именованных символов (nl – для новой строки, ht – для горизонтальной табуляции и т. д.). В листинге 6 показано несколько доступных форматов дампа файла text2 из нашего примера.

Листинг 6. Дампы файлов, созданные с помощью команды od
$ od text2 0000000 004471 066160 066565 031412 061011 067141 067141 005141 0000020 030061 060411 070160 062554 000012 0000031 $ od -A d -t c text2 0000000 9 \t p l u m \n 3 \t b a n a n a \n 0000016 1 0 \t a p p l e \n 0000025 $ od -A n -t a text2 9 ht p l u m nl 3 ht b a n a n a nl 1 0 ht a p p l e nl

Примечания:

Файлы, используемые в наших примерах, очень малы, но иногда вам могут встретиться большие файлы, которые необходимо разделить на несколько более мелких. Например, вам может потребоваться разбить один большой файл на несколько частей такого размера, чтобы их можно было записать на компакт-диски. Для этого можно использовать команду split , которая разбивает файлы таким образом, что впоследствии их можно легко собрать обратно в единый файл при помощи команды cat . По умолчанию имена файлов, создаваемых командой split , состоят из префикса "x", за которым следует суффикс "aa", "ab", "ac", ..., "ba", "bb" и так далее. Эти умолчания можно изменить с помощью различных опций. Вы также можете задавать размер выходных файлов и определять, будут ли они содержать определенное количество строк или просто иметь определенный размер в байтах.

В листинге 7 показано разделение наших двух текстовых файлов с использованием различных префиксов для выходных файлов. Файл text1 мы разделили на файлы, содержащие максимум две строки, а файл text2 – на файлы максимальным размером в 18 байтов. Далее с помощью команды cat мы отобразили некоторые отдельные части, а также весь файл целиком, используя универсализацию файловых имен , которая рассматривается в статье "Основы управления файлами и директориями " (см. ).

Листинг 7. Разделение и восстановление файлов с помощью команд split и cat
$ split -l 2 text1 $ split -b 17 text2 y $ cat yaa 9 plum 3 banana 1$ cat yab 0 apple $ cat y* x* 9 plum 3 banana 10 apple 1 apple 2 pear 3 banana

Обратите внимание на то, что файл с именем yaa не оканчивается символом новой строки, поэтому, когда мы вывели его содержимое на экран с помощью команды cat , наше приглашение сдвинулось вправо.

Команды wc, head и tail

Команда cat выводит полное содержимое файла. Это хорошо подходит для небольших файлов (например, для наших примеров), но что делать, если объем файла очень большой? Итак, для начала можно оценить размер файла с помощью команды wc (W ord C ount – подсчет слов). Команда wc выводит количество содержащихся в файле строк и слов, а также размер файла в байтах, определить который можно также с помощью команды ls -l . В листинге 8 показан подробный вывод сведений о наших двух текстовых файлах, а также вывод команды wc .

Листинг 8. Использование команды wc для работы с текстовыми файлами
$ ls -l text* -rw-rw-r--. 1 ian ian 24 2009-08-11 14:02 text1 -rw-rw-r--. 1 ian ian 25 2009-08-11 14:27 text2 $ wc text* 3 6 24 text1 3 6 25 text2 6 12 49 total

Различные опции позволяют вам управлять выводом команды wc или отображать другую информацию, например, максимальную длину строки. Для получения дополнительной информации обратитесь к man-странице.

Две другие команды позволяют отображать либо первую часть файла (заголовок ), либо последнюю (хвост ). Эти команды так и называются – head и tail соответственно. Их можно использовать в качестве фильтров или передавать им в качестве аргумента имя файла. По умолчанию эти команды отображают 10 первых (или последних) строк файла или потока. В листинге 9 совместно используются команды dmesg (отображение информации о загрузке системы), wc , tail и head ; в результате мы видим, что файл содержит 791 сообщение, выводим последние 10 из них, а затем выводим шесть сообщений, начиная с 15 от конца.

Листинг 9. Использование команд wc, head и tail для вывода сообщений о загрузке
$ dmesg|wc 791 5554 40186 $ dmesg | tail input: HID 04b3:310b as /devices/pci0000:00/0000:00:1a.0/usb3/3-2/3-2.4/3-2.4:1.0/input/i nput12 generic-usb 0003:04B3:310B.0009: input,hidraw1: USB HID v1.00 Mouse on us b-0000:00:1a.0-2.4/input0 usb 3-2.4: USB disconnect, address 11 usb 3-2.4: new low speed USB device using uhci_hcd and address 12 usb 3-2.4: New USB device found, idVendor=04b3, idProduct=310b usb 3-2.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0 usb 3-2.4: configuration #1 chosen from 1 choice input: HID 04b3:310b as /devices/pci0000:00/0000:00:1a.0/usb3/3-2/3-2.4/3-2.4:1.0/input/i nput13 generic-usb 0003:04B3:310B.000A: input,hidraw1: USB HID v1.00 Mouse on us b-0000:00:1a.0-2.4/input0 usb 3-2.4: USB disconnect, address 12 $ dmesg | tail -n15 | head -n 6 usb 3-2.4: USB disconnect, address 10 usb 3-2.4: new low speed USB device using uhci_hcd and address 11 usb 3-2.4: New USB device found, idVendor=04b3, idProduct=310b usb 3-2.4: New USB device strings: Mfr=0, Product=0, SerialNumber=0 usb 3-2.4: configuration #1 chosen from 1 choice input: HID 04b3:310b as /devices/pci0000:00/0000:00:1a.0/usb3/3-2/3-2.4/3-2.4:1.0/input/i nput12

Другим распространенным применением команды tail является слежение за файлом; для этого используется опция -f и шаг, обычно равный одной строке. Это может оказаться полезным в том случае, если у вас имеется фоновый процесс, генерирующий вывод данных в файл, и вы хотите следить за ходом его выполнения. В этом режиме команда tail будет работать и выводить строки по мере их добавления в файл до тех пор, пока вы не завершите ее работу, нажав Ctrl-c .

Команды expand, unexpand и tr

Когда мы создавали наши файлы text1 и text2, в последнем из них были использованы символы табуляции. Иногда вам может потребоваться заменить символы табуляции на символы пробела и наоборот. Для этого предназначены команды expand и unexpand . В обеих командах опция -t позволяет устанавливать позиции табуляции. Если после этой опции указывается только одно значение, то позиции табуляции будут периодически расставляться через этот указанный интервал. В листинге 10 показано, как сократить символы табуляции в файле text2 до одиночных пробелов, а также приведена причудливая последовательность из команд expand и unexpand и нарушающая выравнивание текста в файле text2.

Листинг 10. Использование команд expand и unexpand
$ expand -t 1 text2 9 plum 3 banana 10 apple $ expand -t8 text2|unexpand -a -t2|expand -t3 9 plum 3 banana 10 apple

К сожалению, вы не можете использовать команду unexpand для замены пробелов в файле text1 на символы табуляции, поскольку для преобразования в символ табуляции команде unexpand требуется, как минимум, два последовательных пробела. Однако вы можете использовать команду tr , которая преобразует символы из одного набора (набор1 ) в соответствующие символы из другого набора (набор2 ). В листинге 11 показан пример использования команды tr для преобразования пробелов в символы табуляции. Поскольку команда tr представляет собой фильтр в чистом виде, то входные данные для нее генерируются с помощью команды cat . В этом примере также показан пример использования дефиса (-) с целью указать cat на то, что ввод будет осуществляться со стандартного устройства; таким образом, мы можем объединить вывод команды tr с содержимым файла text2.

Листинг 11. Использование команды tr
$ cat text1 |tr " " "\t"|cat - text2 1 apple 2 pear 3 banana 9 plum 3 banana 10 apple

Если вы не очень понимаете, что происходит в последних двух примерах, то попробуйте использовать команду od , чтобы последовательно выполнить каждую команду конвейера, например:
cat text1 |tr " " "\t" | od -tc

Команды Pr, nl и fmt

Команда pr используется для форматирования файлов перед печатью. По умолчанию заголовок включает в себя имя файла, дату и время создания файла, номер страницы, а также две пустых строки нижнего колонтитула. Когда данные поступают из нескольких файлов или со стандартного устройства ввода, вместо даты и времени создания файла используются текущие дата и время. Можно печатать файлы рядом, каждый в своем столбце, а также управлять многими возможностями форматирования с помощью различных опций. Как обычно, дополнительную информацию вы можете найти на man-странице.

Команда nl нумерует строки, что может оказаться полезным при печати файлов. Для нумерации строк можно также использовать команду cat с опцией -n . В листинге 12 показано, как распечатать наш текстовый файл, пронумеровать строки в файле text2 и вывести его на печать вместе с файлом text1.

Листинг 12. Нумерация строк и форматирование перед печатью
$ pr text1 | head 2009-08-11 14:02 text1 Page 1 1 apple 2 pear 3 banana $ nl text2 | pr -m - text1 | head 2009-08-11 15:36 Page 1 1 9 plum 1 apple 2 3 banana 2 pear 3 10 apple 3 banana

Другой полезной командой для форматирования текста является команда fmt , которая форматирует текст таким образом, чтобы он не выходил за границы полей. Можно объединить несколько коротких строк в одну длинную и наоборот. В листинге 13 мы создали файл text3, используя одну длинную конструкцию из комбинаций символов!#:* (предназначенных для управления историей команд), благодаря чему, напечатанное предложение было сохранено в файле четыре раза. Также мы создали файл text4, содержащий по одному слову в каждой строке. Затем с помощью команды cat мы отобразили содержимое этих файлов в неформатированном виде, включая символ конца строки "$". Наконец, с помощью команды fmt мы отформатировали эти файлы, ограничив максимальное значение длины строки 60 символами. Как обычно, дополнительную информацию вы можете найти на man-странице.

Листинг 13. Форматирование с указанием максимальной длины строки
$ echo "This is a sentence. " !#:* !#:1->text3 echo "This is a sentence. " "This is a sentence. " "This is a sentence. ">text3 $ echo -e "This\nis\nanother\nsentence.">text4 $ cat -et text3 text4 This is a sentence. This is a sentence. This is a sentence. $ This$ is$ another$ sentence.$ $ fmt -w 60 text3 text4 This is a sentence. This is a sentence. This is a sentence. This is another sentence.

Команды sort и uniq

Команда sort сортирует входные данные с использованием схемы упорядочивания локали (LC_COLLATE) системы. Команда sort также может объединять уже отсортированные файлы и определять, является ли файл отсортированным или нет.

В листинге 14 приведены примеры использования команды sort для сортировки двух текстовых файлов после замены в файле text1 пробелов на символы табуляции. Поскольку сортировка выполняется на основе символьных значений, вы можете удивиться, увидев результаты. К счастью, команда sort может выполнять сортировку не только на основе символьных, но также и на основе числовых значений. Вы можете указать требуемый метод сортировки для всей записи или для каждого поля . Если вы не указываете разделитель полей, то используются пробелы или символы табуляции. Во втором примере листинга 14 сортировка первого поля выполняется по числовым значениям, а сортировка второго поля – с использованием схемы упорядочивания (в алфавитном порядке). Также показан пример использования опции -u для удаления повторяющихся строк.

Листинг 14. Сортировка по символьным и числовым значениям
$ cat text1 | tr " " "\t" | sort - text2 10 apple 1 apple 2 pear 3 banana 3 banana 9 plum $ cat text1|tr " " "\t"|sort -u -k1n -k2 - text2 1 apple 2 pear 3 banana 9 plum 10 apple

Заметьте, что в списке все равно присутствуют две строки со словом "apple", поскольку проверка уникальности выполнялась по всем ключам сортировки (в нашем случае это k1n и k2). Подумайте, какие команды нужно изменить или добавить в конвейер в последнем примере, чтобы исключить дублирование слова "apple".

Можно управлять удалением повторяющихся строк с помощью другой команды – uniq . В обычном режиме команда uniq работает с отсортированными файлами и удаляет последовательные повторяющиеся строки из любого файла независимо от того, отсортирован он или нет. Также эта команда может игнорировать заданные поля. В листинге 15 выполняется сортировка наших двух текстовых файлов по второму полю (имя фрукта), после чего удаляются строки, в которых повторяются значения второго поля (т. е. при проверке мы не обращаем внимания на первое поле).

Листинг 15. Использование команды uniq
$ cat text1|tr " " "\t"|sort -k2 - text2|uniq -f1 10 apple 3 banana 2 pear 9 plum

В этом примере сортировка выполнялась с использованием схемы упорядочивания, поэтому команда uniq оставила запись "10 apple", а не "1 apple". Вы можете добавить сортировку первого поля по числовым значениями и посмотреть, что изменится в этом случае.

Команды cut, paste и join

Давайте рассмотрим еще три команды, которые работают с полями в текстовых данных. Эти команды особенно полезны при работе с табличными данными. Первая команда cut извлекает поля из текстовых файлов. Символом-разделителем по умолчанию является символ табуляции. В листинге 16 содержится пример, в котором команда cut используется для разделения двух столбцов файла text2, а затем в качестве разделителя выходных данных используется пробел, что является необычным способом преобразования символов табуляции в пробелы.

Листинг 16. Использование команды cut
$ cut -f1-2 --output-delimiter=" " text2 9 plum 3 banana 10 apple

Команда paste вставляет (склеивает) строки из двух или более файлов, размещая их рядом (подобно тому, как команда pr объединяет файлы с помощью опции -m). В листинге 17 показан результат применения этой команды к нашим текстовым файлам.

Листинг 17. Склеивание файлов
$ paste text1 text2 1 apple 9 plum 2 pear 3 banana 3 banana 10 apple

В этом примере показана простейшая операция, тем не менее, команда paste может вставлять данные из одного или нескольких файлов различными способами. Для получения дополнительной информации обратитесь к man-странице.

Последняя команда для управления полями – это команда join , которая объединяет файлы на основе совпадения полей. Файл должен быть отсортирован по объединяемому полю. Поскольку файл text2 не отсортирован по числовым значениям, то можно отсортировать его, а затем объединить с помощью команды join две строки с одинаковым значением поля, по которому выполняется объединение (в нашем примере это первое поле, содержащее значение 3).

Листинг 18. Объединение файлов по совпадающим полям
$ sort -n text2|join -j 1 text1 - 3 banana banana join: file 2 is not in sorted order

Что же здесь пошло не так? Вспомните материал раздела , в котором говорилось о сортировке на основе числовых и символьных значений. Объединение выполняется по совпадающим символам в соответствии со схемой упорядочивания locale. Объединение не будет выполняться для числовых полей до тех пор, пока все поля не будут иметь одинаковую длину.

Мы использовали опцию -j 1 для объединения по первому полю в каждом файле. Для каждого файла можно указать отдельное поле, по которому будет выполняться объединение. Например, можно объединить поле 3 в одном файле с полем 10 другого файла.

Давайте создадим еще один файл, text5, выполнив сортировку файла text1 по второму полю (имя фрукта), а затем заменив пробелы на символы табуляции. Если теперь мы отсортируем файл text2 по второму полю и объединим его с файлом text5 по этому же полю, то получим два совпадения (apple и banana). Это объединение показано в листинге 19.

Листинг 19. Объединение файлов по совпадающим полям
$ sort -k2 text1|tr " " "\t">text5 $ sort -k2 text2 | join -1 2 -2 2 text5 - apple 1 10 banana 3 3

Редактор Sed

Sed (s tream ed itor) – это потоковый редактор. Ему посвящено несколько статей Web-сайта developerWorks, а также множество книг (см. раздел ). Sed является чрезвычайно мощным инструментом, а круг решаемых им задач ограничен лишь вашим воображением. Этот небольшой обзор должен пробудить ваш интерес к sed, хотя он не является полным и всесторонним.

Как и многие команды для работы с текстом, которые мы здесь рассмотрели, sed может работать как фильтр или принимать входные данные из файла. Вывод осуществляется на стандартное устройство вывода. Sed загружает строки из входных данных в область шаблонов , применяет к ее содержимому команды редактирования и передает ее на стандартное устройство вывода. Sed может объединять в области шаблонов несколько строк; результат может быть записан в файл, может быть записан частично, а может быть не записан вообще.

Для поиска и выборочной замены текста в области шаблонов, а также для определения строк, над которыми необходимо выполнять те или иные команды редактирования, sed использует синтаксис регулярных выражений. Более подробно о регулярных выражениях рассказывается в статье "Поиск в текстовых файлах с помощью регулярных выражений " (см. ). Временным хранилищем текста служит буфер удержания . Буфер удержания может заместить собой область шаблонов, может быть добавлен к области шаблонов, а может обмениваться с ней данными. Хотя в sed имеется ограниченное число команд, их использование совместно с регулярными выражениями и буфером удержания открывает безграничные возможности. Набор команд sed обычно называется сценарием sed .

В листинге 20 показаны три простых сценария sed. В первом сценарии используется команда s (substitute – замена) для замены в каждой строке символа "a" в нижнем регистре на этот же символ в верхнем регистре. В первом примере выполняется замена только первого символа "a", поэтому во втором примере мы добавили флаг "g" (global – глобальный), благодаря которому, будет выполняться замена всех найденных вхождений этого символа. В третьем сценарии мы используем команду d (delete – удалить) для удаления строки. В нашем примере мы использовали адрес 2, чтобы показать, что необходимо удалить только строку с этим номером. Мы разделяем команды точкой с запятой (;) и используем глобальную замену символов "a" на "A", как это было сделано во втором примере.

Листинг 20. Первые шаги по работе со сценариями sed
$ sed "s/a/A/" text1 1 Apple 2 peAr 3 bAnana $ sed "s/a/A/g" text1 1 Apple 2 peAr 3 bAnAnA $ sed "2d;$s/a/A/g" text1 1 apple 3 bAnAnA

Помимо работы с отдельными строками, sed может работать с диапазонами строк. Начало и конец диапазона разделяются запятой (,) и могут определяться в виде номера строки, регулярного выражения или знака доллара ($), означающего конец файла. Зная адрес или диапазон адресов, вы можете сгруппировать несколько команд, заключив их в фигурные скобки { и }; таким образом, эти команды будут работать только с теми строками, которые указаны в диапазоне. В листинге 21 показано два примера глобальной замены, которая применяется только к последним двум строкам нашего файла. Также приведен пример использования опции -e для добавления нескольких команд в сценарий.

Листинг 21. Адреса в sed
$ sed -e "2,${" -e "s/a/A/g" -e "}" text1 1 apple 2 peAr 3 bAnAnA $ sed -e "/pear/,/bana/{" -e "s/a/A/g" -e "}" text1 1 apple 2 peAr 3 bAnAnA

Сценарии sed можно сохранять в виде файлов. Скорее всего, вы захотите использовать эту возможность для наиболее часто используемых сценариев. Вспомните команду tr , которую мы использовали для изменения пробелов в файле text1 на символы табуляции. Давайте теперь сделаем то же самое с помощью сценария sed, сохраненного в файле. Для создания файла мы используем команду echo . Результаты представлены в листинге 22.

Листинг 22. Короткая программа sed
$ echo -e "s/ /\t/g">sedtab $ cat sedtab s/ / /g $ sed -f sedtab text1 1 apple 2 pear 3 banana

Существует множество подобных коротких сценариев; ссылки на некоторые из них вы можете найти в разделе .

В нашем последнем примере сначала используется команда = для вывода номеров строк, а затем выполняется фильтрация полученного вывода с помощью sed (в результате мы получим такой же эффект, как от использования команды nl для нумерации строк). В листинге 23 с помощью команды = выводятся номера строк, затем с помощью команды N вторая строка ввода считывается в область шаблонов и, наконец, между двумя строками в области шаблонов удаляется символ новой строки (/n).

Листинг 23. Нумерация строк с помощью sed
$ sed "=" text2 1 9 plum 2 3 banana 3 10 apple $ sed "=" text2|sed "N;s/\n//" 19 plum 23 banana 310 apple

Не совсем то, что мы хотели получить! Вообще-то, мы ожидали получить выровненный столбец с номерами строк, после которых следуют сами строки файла, отделенные несколькими пробелами. В листинге 24 мы вводим несколько строк с командами (обратите внимание на дополнительное приглашение >). Изучите этот пример и прочитайте его объяснение ниже.

Листинг 24. Нумерация строк с помощью sed, второй подход
$ cat text1 text2 text1 text2>text6 $ ht=$(echo -en "\t") $ sed "=" text6|sed "N > s/^/ / > s/^.*\(......\)\n/\1$ht/" 1 1 apple 2 2 pear 3 3 banana 4 9 plum 5 3 banana 6 10 apple 7 1 apple 8 2 pear 9 3 banana 10 9 plum 11 3 banana 12 10 apple

Вот, что было сделано в этом примере:

  1. Сначала с помощью команды cat мы создали файл, содержащий 12 строк из двух копий файлов text1 и text2 (если бы количество строк оказалось меньше 10, т. е. все числа были бы одного порядка, то не было бы никакого смысла в их форматировании).
  2. В командном интерпретаторе bash клавиша табуляции используется для завершения команды, поэтому удобно иметь заранее определенный символ табуляции для использования в тех случаях, когда он вам потребуется. Для этого с помощью команды echo мы сохранили символ табуляции в переменной окружения "ht".
  3. Мы создали поток, содержащий номера строк и следующие за ними строки с данными, как мы делали это раньше, и отфильтровали его с помощью второй копии sed.
  4. Мы считали вторую строку в область шаблонов.
  5. В начале области шаблонов (обозначаемой символом ^) мы добавили к номеру строки префикс, состоящий из шести пробелов.
  6. Наконец, мы применили выравнивание с помощью разделителя, содержащего последние шесть символов и символ табуляции, и теперь в номера строк в выводе будут выровнены по первым шести символам. Обратите внимание на то, что в левой части команды "s" используются конструкции "\(" и "\)" для отметки символов, которые мы хотим использовать в правой части. В правой части мы ссылаемся на первый (и единственный в нашем примере) такой набор символов с помощью /1. Заметьте, что наша команда заключена в двойные кавычки ("), поэтому эта подстановка будет выполнена для переменной $ht.

Последняя (четвертая) версия редактора sed содержит документацию в формате info и включает множество превосходных примеров. В более старой версии, 3.02, эти возможности отсутствуют. Узнать версию редактора GNU sed можно с помощью команды sed --version .