Согласно определению, данному в стандарте POSIX-2001, текстовым называется
файл, символы которого объединены в строки длиной не более {LINE_MAX}, не
содержащие нулевого символа.
Вероятно, простейшей операцией с файлами (не обязательно текстовыми) является их выдача на стандартный вывод, что обеспечивается посредством утилиты
cat [-u] [файл ...]
Несмотря на внешнюю простоту, применение служебной программы cat сопряжено с
рядом тонкостей. Во-первых, опция -u предписывает передавать на
стандартный вывод байты из входных файлов без задержек, это означает, в частности,
отмену буферизации стандартного вывода. Во-вторых, если не указаны
исходные файлы или в качестве аргумента задан знак минус, используется
стандартный ввод. Минус может фигурировать в командной строке несколько раз,
стандартный ввод не закрывается и не переоткрывается. Например, допустимы
команды, показанные в листинге 6.1, причем первая
обеспечит ввод двух интерактивных вставок, а вторая эквивалентна третьей (читателю
предлагается самостоятельно объяснить данный факт).
cat f1.txt - f2.txt - f3.txt cat g1.txt - g2.txt - g3.txt < input.txt cat g1.txt - g2.txt /dev/null g3.txt < input.txt cat f1.txt f2.txt > f1.txt
В-третьих, нужно учитывать особенности cat выдает результат f1.txt.
Для
more [опция ...] [файл ...]
Она разбивает вывод на
Программа more - довольно мощный cat, а из
опций выделим три.
-n число
Задает число строк, выдаваемых на экран.
-p команды more
Команды more выполняются после входа в очередной файл и вывода его первого
экрана. Это может быть, к примеру, команда поиска.
-s
Сжимать последовательные пустые строки в одну.
Утилита more часто используется как заключительное звено конвейеров для удобного просмотра результатов.
Для
od [опция ...] [файл ...]
Она выдает на стандартный вывод содержимое исходных файлов в формате,
заданном пользователем, а также в виде блоков, каждый из которых в простейшем (и
наиболее употребительном) случае состоит из шестнадцати байт и занимает при
выводе одну строку. В начале подобной строки располагается смещение блока от
начала файла, затем следует содержимое блока. С помощью -A
можно задать основание системы счисления для смещений ( d -
десятичное, o - восьмеричное, x - шестнадцатеричное, n - не выдавать смещение).
Формат выдачи содержимого определяется -t. Помимо
перечисленных типов могут быть заданы a
( c (символы), f (вещественные числа), u (беззнаковые десятичные). За спецификациями d, f, o, u и x
может следовать десятичное число - количество байт в одном значении
заданного типа; за спецификацией f - символы F, D или L, указывающие тип
вещественных чисел ( float, double или long double,
соответственно), а за спецификациями d, o, u, x - спецификаторы целочисленного типа C ( char ), S ( short ), I ( int ) или L ( long ).
Рассмотрим пример. Пусть файл ascii.tab содержит байты от
od -A x -t a ascii.tab
000000 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si
000010 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us
000020 sp ! " # $ % ' ( ) * + , - . /
000030 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
000040 @ A B C D E F G H I J K L M N O
000050 P Q R S T U V W X Y Z [ \ ] ^ _
000060 ` a b c d e f g h i j k l m n o
000070 p q r s t u v w x y z { | } ~ del
000080
Полезная возможность - взглянуть на начало файла, чтобы понять, нуждается ли он в более детальном изучении. Эта возможность реализуется служебной программой head:
head [-n число] [файл ...]
Утилита head копирует на стандартный вывод указанное число (по умолчанию
- 10) начальных строк исходных файлов (или весь файл, если он слишком
короткий).
"Симметричная" служебная программа - tail
tail [-f] [-c число | -n число] [файл]
выдает на стандартный вывод конец исходного файла, начиная с указанного
места. Если задана опция -c, единицей измерения является байт, если -n
- строка. Числовой
Опция -f полезна для слежения за растущими файлами, в которые пишет
какой-либо другой процесс. При наличии этой опции утилита tail не завершается по
достижении конца файла, но ждет появления новых данных и выводит их.
Рассмотрим примеры. Команда
tail -f f1
выдаст последние десять строк файла f1, за которыми последуют строки,
добавленные к файлу f1 в промежуток времени между запуском и терминированием
утилиты tail.
В качестве примера совместного использования служебных программ head
и tail приведем фрагмент одного из командных файлов ОС Linux (см.
листинг 6.4).
echo "Reloading automounter: checking\ for changes ... " TMP=/var/run/autofs.tmp getmounts > $TMP for i in /var/run/autofs.*.pid do pid=`head -n 1 $i 2>/dev/null` [ "$pid" = "" ] continue command=`tail -n +2 $i` if ! grep -q "^$command" $TMP then echo "Stopping automounter: $command" kill -USR2 $pid fi done rm -f $TMP
Отметим, что здесь утилиты head и tail делят исходный файл
"по-братски": первой достается первая строка, второй - все остальные.
Служебная программа pr
pr [+номер_страницы] [-число_столбцов] [-adFmrt] [-e[символ][число]] [-h заголовок] [-i[символ][число]] [-l число_строк] [-n[символ][ширина]] [-o отступ] [-s[символ]] [-w ширина] [файл ...]
является
Утилита pr обрабатывает следующие аргументы командной строки.
+номер_страницы
Начать вывод со
-число_столбцов
Вывод в заданное число -e и -i.
Этот аргумент несовместим с опцией -m.
-a
Выдача в несколько
-d
Выдача через строку.
-e[символ][число]
Установка табуляции через заданное число позиций, начиная с первой. Символы табуляции во входном файле развертываются в соответствующее количество пробелов. Если задан любой нецифровой символ, он трактуется как символ табуляции во входном файле.
-F
Применять символы перехода к новой
-h заголовок
Использовать заданный
-i[символ][число]
При выводе, где это возможно, последовательности пробельных символов заменяются символами табуляции, при условии, что табуляции установлены через заданное число позиций, начиная с первой. Если задан любой нецифровой символ, он выводится в качестве символа табуляции.
-l число_строк
Установка длины
-m
-n[символ][ширина]
Производится нумерация строк. Под номер отводится поле заданной ширины (по умолчанию - 5). Если задан любой нецифровой символ, то он присоединяется к номеру строки, отделяя ее от последующего текста (подразумеваемым значением является символ табуляции).
-o отступ
Установка
-p
Пауза перед выдачей каждой pr включит звонок и будет ждать нажатия клавиши возврата каретки).
-r
Подавление диагностических сообщений при ошибках открытия файлов.
-s[символ]
Разделение
-t
Подавление выдачи пятистрочного идентифицирующего
-w ширина
Установка ширины строки (по умолчанию - 72 позиции). Эта опция действует
только при печати в несколько
В качестве примера использования служебной программы pr приведем
конвейер, позволяющий получить пронумерованный список всех файлов текущего
ls -a | pr -2 -a -l 24 -n' '3 -h "Список\ файлов каталога $(pwd)"
Начальный фрагмент результата может выглядеть так, как показано в листинге 6.5.
2003-10-17 17:24 Список файлов каталога /var/tmp Page 1 1 . 2 .. 3 Blank.ReS 4 Make45.ReS 5 Make46.ReS 6 from_cvs 7 gcc-20032204 8 gcc-3.4-16-jun-2003 9 htdocs 10 rpm-tmp.29785 . . .
Для подсчета числа символов,
wc [-c | -m] [-w] [-l] файл ...
Опция -c предписывает подсчитывать байты, -m - символы, -w - -l
- строки. По умолчанию подсчитываются символы,
Рассмотрим пример. Предположим, что результаты, показанные в
листинге 6.3,
сохранены в файле ascii.od. Тогда команда, приведенная в
листинге 6.6, выдаст
результат, показанный в листинге 6.7.
wc ascii.od
9 137 575 ascii.od
Иными словами, в указанном файле 575 символов, 137 слов, расположенных на 9 строках.
Служебная программа sort
sort [-m] [-o выходной_файл] [-bdfinru] [-t символ] [-k определение_ключа] ... [файл ...] sort -c [-bdfinru] [-t символ] [-k определение_ключа] [файл]
в зависимости от заданных опций выполняет одно из трех возможных действий:
При упорядочении используется один или несколько
Следующие опции управляют порядком работы утилиты sort.
-c
Проверить, является ли (единственный) исходный файл уже
-m
-o выходной_файл
Результат направляется не на стандартный вывод, а в выходной_файл, который
может совпадать с одним из исходных.
-u
Опция уникальности: из всех совпадающих строк выводить только одну, при
наличии опции -c контролировать отсутствие строк с совпадающими
Следующие опции изменяют подразумеваемый способ сравнения. Если они
употреблены независимо от определения
-d
"Словарный" порядок: при сравнении являются значимыми только буквы, цифры и пробельные символы.
-f
При сравнении преобразовывать малые буквы в большие.
-i
При сравнении игнорировать непечатные символы.
-n
Числовое сравнение. Ограничить
-r
Заменить результат сравнения на противоположный.
Следующие опции изменяют трактовку
-b
Игнорировать начальные пробельные символы при определении начала и конца -b указана перед первой опцией -k, она воздействует на все
ключи, снабженные опцией -k.
-t символ
Использовать заданный символ как -t подразумеваемыми разделителями становятся
пробельные символы, точнее, максимальная непустая последовательность таких
символов, а в поле включаются предшествующие ему разделители.
-k. Определение ключа имеет
следующий формат:
начало_поля[тип][,конец_поля[тип]]
Ключевое поле охватывает все позиции - от начальной до конечной, которые задаются, соответственно, как
номер_поля[.первый_символ] номер_поля[.последний_символ]
Тип - это один из модификаторов b, d, f, i, n, r.
Модификатор b ведет себя аналогично опции -b,
но применяется только к той границе ключа, после
которой он указан. Остальные модификаторы также аналогичны одноименным
опциям, но воздействуют на ключ в целом.
Если указано несколько -k ), то более поздние используются только в случае равенства более ранних. Если
значения
Приведем примеры использования служебной программы sort. Автор хранит данные
о собственном кровяном давлении в виде файла pp.txt, содержащего пять
12.05.2000 17:30 200 125 120 15.05.2000 17:00 130 80 70 17.05.2000 10:30 150 90 70 17.05.2000 21:45 154 99 74 19.05.2000 10:05 158 83 89 21.05.2000 21:00 161 104 64 22.05.2000 21:00 147 104 69 . . .
sort -r -k 3,3 pp.txt
12.05.2000 17:30 200 125 120 18.11.2000 19:30 172 107 68 04.07.2002 09:00 170 98 85 30.10.2001 13:00 168 94 88 27.12.2000 20:30 166 98 69 23.05.2002 10:00 166 104 56 22.05.2002 10:00 166 103 57 23.10.2001 11:00 165 88 88 . . .
Если
# Первый вариант - ключ сортировки покрывает # несколько полей sort -r -k 3,5 pp.txt # Второй вариант - используется несколько # ключей сортировки # sort -n -r -k 3,3 -k 4,4 -k 5,5 pp.txt
12.05.2000 17:30 200 125 120 18.11.2000 19:30 172 107 68 04.07.2002 09:00 170 98 85 30.10.2001 13:00 168 94 88 23.05.2002 10:00 166 104 56 22.05.2002 10:00 166 103 57 27.12.2000 20:30 166 98 69 23.10.2001 11:00 165 88 88 . . .
Предположим теперь, что данные о давлении и пульсе разбиты по годам и в уже pp2000.sorted, pp2001.sorted и т.д. Для их
# Первый вариант слияния файлов
# sort -m -o pp.sorted -n -r -k 3,3 -k 4,4
# -k 5,5 pp2*.sorted
# Второй вариант слияния файлов
> pp.sorted
for f in pp2*.sorted
do
sort -m -o pp.sorted -n -r -k 3,3\
-k 4,4 -k 5,5 $f pp.sorted
done
Проверить правильность
name=pp.sorted
if sort -c -r -n -k 3,3 -k 4,4 -k 5,5 $name
then
echo Данные в файле $name отсортированы\
верно
elif
echo Данные в файле $name отсортированы\
неверно
fi
Содержимое файлов f1 и f2 сортирует команда (см. листинг 6.15) , применяющая в качестве ключа второй непробельный символ второго поля.
sort -k 2.2b,2.2b f1 f2
sort -t ':' -k 3,3n /etc/passwd
Выдать содержимое уже f.sorted, выводя лишь первую
из строк с одинаковыми третьими полями, поможет комбинация опций -m и -u
(см. листинг 6.17).
sort -um -k 3.1,3 f.sorted
В ситуациях, когда есть две версии текста - "правильная" и
"неправильная" (например, исходные тексты работающей и неработающей программ),
полезно понять, чем они отличаются. Для этого предназначена служебная
программа diff:
diff [-c | -e | -f | -C число] [-br]
файл1 файл2
Утилита diff сравнивает содержимое исходных файлов и выдает на стандартный
вывод список изменений, которые необходимо произвести, чтобы
преобразовать файл1 в файл2. Она поддерживает следующие опции.
-b
Игнорировать пробельные символы в конце строк; остальные
-c
Производить вывод в формате, обеспечивающем три строки контекста.
-C число
Производить вывод в формате, обеспечивающем заданное число строк контекста.
-e
Производить вывод в формате, пригодном для подачи на вход редактора ed и
преобразования файла1 в файл2.
-f
Производить вывод в альтернативном формате, напоминающем -e, но в обратном
порядке и не предназначенном для подачи на вход редактора ed.
-r
Если файл1 и файл2 представляют собой diff рекурсивно к одноименным и однотипным обычным файлам и
В качестве примера использования служебной программы diff сравним две
версии бинарных утилит (см. листинг 6.18).
Начальный фрагмент результата
показан в листинге 6.19.
Видно, что различия, по сути, сводятся к добавлению
новых файлов.
diff -r binutils-2_14 binutils-2_14-branch
diff -r binutils-2_14/bfd/version.h binutils-2_14-branch/bfd/version.h 1c1 < #define BFD_VERSION_DATE 20030612 --- > #define BFD_VERSION_DATE 20031007 Only in binutils-2_14-branch/binutils: ChangeLog Only in binutils-2_14-branch/binutils: arlex.c Only in binutils-2_14-branch/binutils: deflex.c Only in binutils-2_14-branch/binutils: rclex.c Only in binutils-2_14-branch/binutils: syslex.c Only in binutils-2_14-branch: config.guess Only in binutils-2_14-branch/gas: ChangeLog Only in binutils-2_14-branch/gas/config: tc-ns32k.c Only in binutils-2_14-branch/gas: configure Only in binutils-2_14-branch/gas: configure.in Only in binutils-2_14-branch/gas: itbl-lex.c . . .
Если нужно проверить два файла на совпадение, предпочтительнее
воспользоваться не утилитой diff, а более простой и быстрой служебной
программой cmp:
cmp [-l | -s] файл1 файл2
По умолчанию cmp выдает на стандартный вывод номера байта и строки, где
встретилось первое отличие. Опция -l предписывает выдавать все отличия в виде
номеров и содержимого (восьмеричного) байт. По опции -s отличия не выдаются,
возвращается лишь соответствующий код завершения (0 - файлы совпадают, 1 -
файлы различаются, больше единицы - зафиксирована ошибка).
Если в продолжение примера с утилитой diff сравнить две версии файла version.h посредством cmp
(см. листинг 6.20), результат будет выглядеть так,
как показано в листинге 6.21.
cmp -l binutils-2_14/bfd/version.h\ binutils-2_14-branch/bfd/version.h
30 60 61 31 66 60 32 61 60 33 62 67
Еще одно средство выявления различий (и, кроме того, совпадений)
текстовых файлов - служебная программа comm:
comm [-123] файл1 файл2
Она читает файл1 и файл2 (их содержимое должно быть
Опции -1, -2 или -3
подавляют вывод соответствующих comm -12 выводит строки, общие для обоих файлов, comm -23 -
имеющиеся только в файле1, comm -123 не выводит ничего.
В стандарте POSIX-2001 приведен следующий пример использования
служебной программы comm. Пусть файл xcu содержит - аналогичный список для
спецификации X/Open Portability Guide, Issue 3, а файл svid89 представляет собой
отсортированный список утилит из System V
comm -12 xpg3 svid89 | comm -23 - xcu
Для
cksum [файл ...]
Для каждого файла - аргумента она выдает на стандартный вывод
подсчитанную по стандарту ISO/IEC 8802-3:1996 (Ethernet)
Применение утилиты cksum - полезный элемент оформления поставляемых
приложений.
Понятие
Когда хотят подчеркнуть составной характер
Стандарт накладывает на сложность (полных) РВ единственное ограничение: реализация должна поддерживать любое РВ, длина которого не превышает 256 байт.
Оговаривается, что при наличии альтернатив выбирается самая левая из возможных цепочек, имеющая к тому же максимальную длину.
Различают
Минимальным элементом
\ следует любой . [ \Эти символы имеют специальный смысл, за исключением случая, когда они заключены в квадратные скобки.
*Символ имеет специальный смысл, если он не заключен в квадратные скобки или не является первым символом
^Символ имеет специальный смысл в начале полного
$Символ имеет специальный смысл в конце полного
[ ]
представляет собой ^,
то Внутри квадратных скобок можно использовать также конструкции, описываемые ниже.
-. Например, [0-9]
эквивалентно [0123456789]. Минус теряет свой специальный смысл, если он стоит в
начале (допустимо после ^ ) или в конце [%--] успешно
сопоставляется со всеми символами от процента до минуса включительно.
Закрывающая квадратная скобка не рассматривается как окончание ^ ).
Таким образом, []a-f]
определяет либо закрывающую квадратную скобку,
либо любой символ от a до f включительно.
Стандарт POSIX-2001 предусматривает поддержку
[:alnum:] [:cntrl:] [:lower:] [:space:] [:alpha:] [:digit:] [:print:] [:upper:] [:blank:] [:graph:] [:punct:] [:xdigit:]
Например, [^[:alnum:]] удовлетворяют символы, отличные от букв и цифр.
В некоторых языках [[.ch.]].
Если определены классы элементов, эквивалентных при алфавитном
сравнении, то подобный класс можно задать, заключив любой его ([= и =]).
Таковы правила построения заключенных в квадратные скобки односимвольных
Построение
\( и \). \n (где n -
цифра от 1 до 9). n, считая от начала полного \(.\)\1 удовлетворяют пары одинаковых символов.\(.*\)\1 удовлетворяют пары стоящих рядом одинаковых
цепочек символов.\{m\}, \{m,\} или \{m,n\} m и n должны
удовлетворять неравенствам^
( $ ( ^\(.*\)\1$
успешно сопоставляется с Операции построения
Опишем отличия
|.| и
имеет низший приоритетa((bc)|d) успешно
сопоставляется и с "abc",
и с "ad". Односимвольные | и заключенные в круглые скобки, трактуются как односимвольные.Таковы правила построения и обработки
Мы приступаем к описанию наиболее употребительных служебных программ и
функций, использующих механизм grep:
grep [-E | -F] [-c | -l | -q] [-insvx]
-e список_шаблонов ...
[-f файл_шаблонов] ... [файл ...]
grep [-E | -F] [-c | -l | -q] [-insvx]
[-e список_шаблонов ...]
-f файл_шаблонов ... [файл ...]
grep [-E | -F] [-c | -l | -q] [-insvx]
список_шаблонов [файл ...]
Она служит для выборки строк исходных файлов, удовлетворяющих хотя бы одному шаблону из заданного списка.
Три приведенные выше варианта вызова служебной программы grep
отличаются способом задания списка шаблонов. В первом случае он является
-e, во втором извлекается из файла шаблонов - аргумента
опции -f, в третьем указывается как самостоятельный аргумент командной
строки, но отдельные элементы этого списка всегда разделяются символами
перевода строки. Опция -e полезна в ситуациях, когда нужно задать шаблон,
начинающийся со знака минус.
По умолчанию шаблоны трактуются как -E предписывает переход к -F означает, что в
качестве шаблонов выступают
Опции -c, -l, -q и -n
влияют на выдачу результатов. По умолчанию на
стандартный вывод выдаются строки исходных файлов, в которых присутствуют
успешно -c предписывает выдавать
только общее число подобных строк, -l - только имена файлов, где
имеются успешно -q - только код завершения (0 - есть
успешно -n требует ставить ее номер в исходном файле
перед каждой выводимой строкой (нумерация строк начинается с 1).
Опции -i, -v и -x воздействуют на процесс -i предписывает не
различать при -v - выбирать строки,
не удовлетворяющие ни одному из заданных шаблонов, -x - рассматривать
только строки, все символы которых участвуют в успешном
Опция -s подавляет выдачу диагностических сообщений о том, что исходный
файл не существует или не доступен на чтение.
Отметим, что опции -F и -q, каждая по-своему,
ускоряют работу служебной
программы grep: -F упрощает -q позволяет завершить -q и -s позволяет также более свободно
задавать исходные файлы, не заботясь об их существовании и доступности.
Рассмотрим примеры использования утилиты grep. Для выборки пустых строк из файла
стандартного ввода пригодны два шаблона:
grep ^$ grep -v .
Если нужно выбрать строки, имеющие вид abc или def, можно воспользоваться одной из трех команд:
grep -E '^abc$|^def$' grep -F -x 'abc def'
И наконец, пусть в файлах с исходными текстами Фортран-программ требуется найти все строки, содержащие вызовы подпрограмм и не являющиеся комментариями. Для такой выборки "в первом приближении" (учитывая нерегулярний синтаксис Фортрана) подойдет следующая команда:
grep -i '^[^C].* CALL ' *.for
В командных файлах для обработки текстов часто используется sed:
sed [-n] сценарий [файл ...]
sed [-n] [-e сценарий] ...
[-f файл_сценария] ... [файл ...]
Редактор sed читает указанные текстовые файлы (по умолчанию -
стандартный ввод), выполняет редактирование в соответствии с командами -e и -f
аналогичен утилите grep. Опция -n подавляет подразумеваемый вывод и
предписывает выдавать только явно отобранные строки.
Сценарий для sed состоит из редактирующих команд (каждая на отдельной строке),
имеющих следующий формат:
[адрес [, адрес]] функция [аргумент ...]
Функция имеет здесь однобуквенное обозначение.
В нормальном режиме sed циклически выполняет следующие
D.-n, копирует буфер на стандартный вывод, добавив
в конце перевод строки. Очищает буфер.Некоторые команды используют хранилище, чтобы запомнить весь буфер или его часть для последующего применения.
Адрес в редактирующей команде sed - это либо десятичное число,
означающее номер входной строки в совокупности входных файлов, либо символ $,
который обозначает последнюю входную строку, либо /базовое_регулярное_выражение/.
Командная строка без адреса применима к любому буферу, командная строка с одним адресом - к буферу с соответствующим адресом, командная строка с двумя адресами - к буферам с адресами в диапазоне от первого до второго включительно; затем процесс повторяется, начиная с первой строки вслед за выбранным диапазоном.
Перечислим команды редактора sed. В скобках указывается максимальное число
допустимых адресов для каждой функции.
Аргумент текст состоит из одной или более строк. Все строки, кроме последней,
заканчиваются на \, чтобы экранировать символ перевода строки.
(2){ функция
функция
...
}
Выполнить заданную последовательность функций.
(1)a\ текст
Добавить. Вывести текст перед чтением следующей входной строки.
(2)b [метка]
Перейти к команде :, содержащей метку.
Если метка пуста, перейти на конец
(2)c\ текст
Заменить. Удалить содержимое буфера. При 0 или 1 адресе или в конце двухадресного диапазона вывести текст. Начать новый цикл.
(2)d
Удалить содержимое буфера. Начать новый цикл.
(2)D
Удалить начало буфера до первого перевода строки. Начать новый цикл.
(2)g
Заменить содержимое буфера содержимым хранилища.
(2)G
Добавить к содержимому буфера содержимое хранилища.
(2)h
Заменить содержимое хранилища содержимым буфера.
(2)H
Добавить к содержимому хранилища содержимое буфера.
(1)i\ текст
Вставить. Вывести текст.
(2)l
Вывести буфер, заменяя непечатные символы на пары символов ASCII и разбивая длинные строки.
(2)n
Скопировать буфер на стандартный вывод, если подразумеваемый вывод не подавлен.
Заменить содержимое буфера на следующую входную строку. Если таковой не
оказалось, завершить выполнение
(2)N
Добавить к буферу следующую входную строку, вставив перед ней символ перевода
строки. (Текущий номер строки изменяется.) Если входных строк больше нет,
завершить выполнение
(2)p
Скопировать буфер на стандартный вывод.
(2)P
Скопировать начальный сегмент буфера (до первого перевода строки) на стандартный вывод.
(1)q
Выйти. Перейти на конец
(2)r ч_файл
Прочитать содержимое ч_файла. Поместить его на стандартный вывод перед чтением
следующей входной строки.
(2)s/БРВ/замена/флаги
Подставить замену вместо фрагментов буфера, отождествленных с
n - заменить n-е вхождение g - заменить все вхождения p - если замена произошла, вывести содержимое буфера;w з_файл - если замена произошла, добавить содержимое буфера к з_файлу.Вместо символа в замене подставляется
(2)t [метка]
Проверить. Перейти к команде :, содержащей метку, если со времени последнего
чтения входной строки или последнего выполнения команды t в буфере
производились подстановки. Если метка пуста, перейти на конец
(2)w з_файл
Записать. Добавить содержимое буфера к з_файлу.
(2)x
Обменять содержимое буфера и хранилища.
(2)y/цепочка1/цепочка2/
Заменить все символы буфера, содержащиеся в цепочке1, на соответствующие
символы цепочки2. Длины цепочек должны совпадать.
(2)! функция
Отрицание. Применить функцию (или группу, если функция начинается с { ) только к
строкам, не соответствующим адресам.
(0): метка
Не делает ничего. Содержит лишь метку, на которую может быть осуществлен переход командами t или b.
(1)=
Вывести в качестве отдельной строки номер текущей строки.
(0)
Пустая команда.
(0)#
#n,
подразумеваемый вывод подавляется (что эквивалентно опции -n в командной строке). В
остальных случаях игнорировать # и остаток строки.
Последовательность символов \n успешно сопоставляется с переводом строки.
Явный символ перевода строки не должен использоваться в
Приведем примеры использования sed. В процессе загрузки
ОС Linux выполняются командные строки, аналогичные показанным в
листинге 6.23.
map=`basename $map | sed -e s/^auto_home/auto.home/ -e s/^auto_mnt/auto.mnt/` cat /etc/auto.master | grep -v '^+' | sed -e '/^#/d' -e '/^$/d'
Первая из них заменяет подчеркивание на точку в именах файлов, обслуживающих
автомонтирование файловых систем, вторая отсеивает строки файла auto.master,
начинающиеся с символа + (это делает grep -v ), комментарии
(строки, начинающиеся символом #) и пустые строки.
Следующий вызов sed (см.
листинг 6.24) сжимает несколько идущих подряд пустых
строк в одну.
sed -n '
p
/^$/ {
# Текущая строка - пустая.
# Добавляем следующие строки к буферу,
# пока он остается пустым.
# Тем самым игнорируются "лишние" пустые
# строки.
:Empty
n
/^$/ b Empty
# Добавленная строка оказалась непустой.
# Выведем ее.
p
}
'
Любопытно сопоставить приведенный нами
sed -n '
# Выведем непустые строки
/./ {
p
d
}
# Выведем одну пустую строку, затем
# проанализируем следующие.
/^$/ p
# Прочитаем следующую строку, отбросим
# оставшийся перевод строки (пустую строку)
# и вернемся к проверке пустой строки.
:Empty
/^$/ {
N
s /.//
b Empty
}
# Выведем непустую строку, затем вернемся к
# поиску первой пустой.
p
'
Еще одно популярное средство обработки текстовых файлов -
служебная программа :
awk [-F РРВ] [-v присваивание] ...
программа [аргумент ...]
awk [-F РРВ] -f программный_файл ...
[-v присваивание] ... [аргумент ...]
Утилита выполняет программы, написанные на одноименном языке
программирования, специально предназначенном для обработки текстов. Программа на
языке представляет собой последовательность шаблонов и
соответствующих
шаблон { действие }
Ввод для делится на обрабатывает ввод построчно. RS. Каждая FS или указав
опцию -F с аргументом - $1, $2,...; $0 - вся входная строка.
Каждая исходная строка сопоставляется с каждым из шаблонов; в случае успеха
выполняются указанные
Действие есть последовательность
if ( условие ) оператор [ else оператор ];while ( условие ) оператор;for ( выражение; условие; выражение ) оператор;break;continue;{ [ оператор ] ... };переменная = выражение # оператор присваивания;print [ список_выражений ] [> выражение ];printf формат [, список_выражений ] [> выражение ];next # пропустить оставшиеся шаблоны и перейти к следующей строке;exit # пропустить оставшиеся строки.список_выражений означает всю строку. +, -, *, /, %, ^ (возведение в степень) и
конкатенации (обозначается пробелом). В них также можно использовать операции из
языка C: ++, --, +=, -=, *=, /=, %=, ^=, ?: (условное x[i] ) или
print выдает свои аргументы на
стандартный вывод (или в файл, если присутствует часть >выражение), разделяя их текущим printf делает то же, но под управлением формата.
Язык содержит большое число
Математические функции atan2 (y, x), cos (x), sin (x), exp (x), log (x), sqrt (x) не
нуждаются в пояснениях. Функция int (x) отбрасывает дробную часть своего
аргумента, rand () возвращает псевдослучайное число в диапазоне от
В число функций, оперирующих gsub (РРВ, замена[, цепочка]) и sub (РРВ, замена[, цепочка])
- соответственно,
глобальная и однократная $0 или s редактора sed и ее флагом g; index
( length [([цепочка])] -
вычисление длины $ ); match> (цепочка, РРВ) - поиск вхождения RSTART и RLENGTH (см. далее); split (цепочка, массив[, РРВ-разделитель]) - расщепление sprintf (формат, выражение, выражение, ...) - формирование substr (цепочка, m[, n]) - выделение
n-символьной m ; tolower (цепочка) - приведение
к строчным буквам; toupper (цепочка) - приведение к прописным буквам.
В языке имеются также группа функций ввода/вывода и функции общего
назначения. Функция close (выражение) закрывает файл или канал, поименованный
заданным getline [переменная]
обеспечивает чтение записи из
текущего входного файла (возможно использование конвейера вида | getline [переменная] и перенаправление ввода getline [переменная] < выражение ), system (выражение) - выполнение команды, заданной
Язык допускает определение пользовательских функций, для чего служит конструкция
function имя_функции ([аргумент, ...])
{ операторы }
Шаблон в языке - это произвольная логическая комбинация,
составленная с помощью операций !, ||,
и скобок из /. Отдельное
выражение опер_сопост РРВ выражение опер_сравн выражение
Здесь опер_сравн - любая из шести операций сравнения языка C, опер_сопост - это ~ (успешно сопоставляется)
или !~ (не сопоставляется).
Условие - арифметическое
Для выполнения каких-либо BEGIN и END.
Шаблон BEGIN следует указывать первым, END - последним.
Присваивания, заданные в командной строке с помощью опции -v, выполняются до начала
интерпретации BEGIN ). Например, для использования символа c в качестве -v 'FS = c'.
В командной строке можно указать также аргументы двух типов -
имена файлов с исходными данными и присваивания. Последние выполняются
непосредственно перед чтением указанного следующим исходного файла. В частности,
присваивания, заданные перед первым аргументом-файлом выполняются после BEGIN, а те, что расположены в конце
командной строки, - перед END. Если в
командной строке нет аргументов-файлов, присваивания выполняются перед
обработкой стандартного ввода.
Перечислим
ARGC
ARGV
Массив аргументов командной строки , исключая опции и программы.
CONVFMT
Формат для преобразования чисел в OFMT, см. далее). По умолчанию - %.6g.
ENVIRON
Массив, представляющий окружение. Индексами служат
FILENAME
Имя файла, из которого в данный момент производится ввод.
FNR
Порядковый номер текущей
FS
NF
Количество
NR
Порядковый номер текущей
OFMT
Формат вывода чисел, по умолчанию %.6g.
OFS
ORS
RLENGTH
Длина успешно match()
RS
Первым символом RS, является RS пусто, между записями может располагаться несколько пустых строк.
RSTART
Начальная позиция успешно match()
SUBSEP
Приведем примеры использования утилиты . Сложить числа, стоящие в первом
{ s += $1 } END { print "Сумма:", s,
" Среднее арифметическое:", s/NR }
Командная строка из
листинга 6.27, служит для вывода тех строк файла f1.txt, у
которых первое
awk '$1 != prev { print; prev = $1 }' f1.txt
Чтобы распечатать файл f2.txt, вставляя после prog. ) и командной строкой, представленными,
соответственно, в листингах
6.28 и 6.29.
/Page/ { $2 = n++ } { print }
awk -f prog.awk -v 'n=1' f2.txt
Программа, показанная в
листинге 6.30, выводит
{ for (i = NF; i > 0; --i) print $i }
Промоделировать работу утилиты echo можно с помощью
BEGIN {
for (i = 1; i < ARGC; ++i)
printf ("%s%s", ARGV [i],
i == ARGC - 1 ? "\n" : " ")
}
Следующая PATH,
по элементам массива.
BEGIN {
n = split (ENVIRON ["PATH"], path, ":")
for (i = 1; i <= n; ++i)
print path [i]
}
В листинге 6.33 приведен фрагмент командного файла, выполняемого при
выключении системы. Здесь можно обратить внимание на разные виды экранирования.
(Третье mount - это точка монтирования.)
# Перемонтируем на чтение все, что еще остается смонтированным.
mount | awk '/( \/ |^\/dev\/root)/ { print $3 }' | while read line; do
mount -n -o ro,remount $line
done
Отметим, что в POSIX-2001 стандартизована весьма развитая версия , входной
язык которой приближен к языку C.
На уровне функций работа с regex (см. листинг 6.34).
#include <regex.h>
int regcomp (regex_t *restrict preg,
const char *restrict pattern, int cflags);
int regexec (const regex_t *restrict preg,
const char *restrict string,
size_t nmatch, regmatch_t
pmatch [restrict], int eflags);
void regfree (regex_t *preg);
size_t regerror (int errcode, const regex_t
*restrict preg, char *restrict errbuf,
size_t errbuf_size);
Первый член этого семейства, функция regcomp(), pattern, и помещает результат компиляции в
структуру типа regex_t, на которую указывает аргумент preg. Эта структура,
описанная в заголовочном файле <regex.h>, должна содержать про крайней мере
size_t re_nsub; /* Число заключенных в скобки подвыражений */
Третий аргумент функции regcomp(), cflags, задается как побитное ИЛИ
следующих флагов:
REG_EXTENDED
Использовать
REG_ICASE
При
REG_NOSUB
В regexec() сообщать только об успехе/неудаче re_nsub структуры regex_t ).
REG_NEWLINE
Изменить трактовку переводов строк (мы не будем на этом останавливаться).
Функция regexec() сопоставляет string со скомпилированным шаблоном, заданным аргументом preg.
При успешном выполнении результат равен нулю; в противном случае возвращается ненулевое значение,
свидетельствующее о неудаче eflags - побитное
ИЛИ флагов REG_NOTBOL и REG_NOTEOL - определяет, являются ли границы ^ и $. Если
значение аргумента nmatch равно нулю или при вызове regcomp() был задан флаг REG_NOSUB, аргумент pmatch функции regexec() игнорируется.
В противном случае он должен указывать на массив не менее чем из nmatch элементов, который
будет заполнен смещениями pmatch [0] соответствует всему
Структурный тип regmatch_t должен включать по крайней мере следующие
regoff_t rm_so; /* Смещение в байтах начала подцепочки от начала цепочки */ regoff_t rm_eo; /* Смещение в байтах первого символа за концом подцепочки от начала цепочки */
Тип regoff_t определяется как целое со знаком, способное вместить любое
значение типов off_t и ssize_t.
Функция regfree() освобождает память, запрошенную вызовом regcomp() с тем же
значением аргумента preg, которое после этого нельзя использовать как
указатель на
В файле <regex.h> определены константы, возвращаемые
функциями семейства regex() в случае ошибки. Например, значение REG_NOMATCH
возвращается функцией regexec() при неудаче REG_BADPAT
обозначает некорректное REG_ESPACE - нехватку
памяти и т.д. Функция regerror() отображает эти константы в
неспецифицируемые стандартом errbuf.
Приложение, вызывая regerror(), должно передать в качестве аргумента errcode
последнее ненулевое значение, возвращенное функциями regcomp() или regexec()
с заданным значением аргумента preg.
Приведем пример использования функций семейства regex() (см.
листинг 6.35).
Обратим внимание на задание флага REG_NOTBOL при повторных обращениях к regexec().
#include <stdio.h>
#include <limits.h>
#include <regex.h>
/* Программа ищет все вхождения заданного шаблона во всех входных строках */
/* и выводит успешно сопоставленные подцепочки */
#define PATTERN "[A-Za-z][A-Za-z0-9]{0,31}"
int main (void) {
char line [LINE_MAX]; /* Буфер для входных строк */
char *pline; /* Указатель на начало сопоставляемой части строки */
regex_t cere; /* Скомпилированное расширенное регулярное выражение */
regmatch_t pm; /* Структура для запоминания границ сопоставленной подцепочки */
int reerrcode; /* Код ошибки от regcomp или regexec */
char reerrbuf [LINE_MAX]; /* Буфер для строк с сообщениями об ошибках */
int i;
if ((reerrcode = regcomp (cere, PATTERN, REG_EXTENDED)) != 0) {
(void) regerror (reerrcode, cere, reerrbuf, sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (cere);
return (reerrcode);
}
fputs ("Вводите строки, сопоставляемые с шаблоном " PATTERN "\n", stdout);
while (fgets (line, sizeof (line), stdin) != NULL) {
/* Произведем первое сопоставление с прочитанной строкой. */
/* Оно отличается от остальных при наличии в шаблоне фиксатора начала */
reerrcode = regexec (cere, pline = line, 1, pm, 0);
while (reerrcode == 0) {
/* Повторяем, пока сопоставления с остатком строки успешны */
fputs ("Сопоставленная подцепочка: ", stdout);
for (pline += pm.rm_so, i = pm.rm_eo - pm.rm_so; i-- > 0; ) {
fputc (*pline++, stdout);
}
fputc ('\n', stdout);
reerrcode = regexec (cere, pline, 1, pm, REG_NOTBOL);
}
}
regfree (cere);
return (ferror (stdin) || ferror (stdout));
}
Читателю рекомендуется поэкспериментировать с шаблоном PATTERN, пробуя
различные варианты, в том числе некорректные.
Идейно простым, но весьма мощным и полезным средством обработки текстовых
файлов является служебная программа преобразования символов tr:
tr [-c | -C] [-s] цепочка1 цепочка2 tr -s [-c | -C] цепочка1 tr -d [-c | -C] цепочка1 tr -ds [-c | -C] цепочка1 цепочка2
Она не применяет
Утилита tr копирует стандартный ввод на стандартный вывод с заменой либо
удалением выбранных символов. При отсутствии опций введенные символы,
найденные в цепочке1, заменяются на соответствующие (стоящие на тех же
относительных позициях) символы из цепочки2.
Опции -c и -C предписывают
использовать вместо цепочки1 ее дополнение до множества всех символов; в первом
случае дополнение упорядочивается в соответствии с кодировкой, во втором
- по алфавиту. По опции -d будут удалены все входные символы, заданные цепочкой1. Опция -s задает
Чтобы задавать в tr группы символов,
можно воспользоваться следующими конструкциями.
c1-c2
Обозначает c1 до c2 включительно.
[:класс_символов:]
Обозначает
[=класс_эквивалентности=]
Обозначает
[c*n]
Обозначает символ c, повторенный n раз.
Может использоваться только в цепочке2.
Если первая цифра в n есть 0, n рассматривается как восьмеричное число;
иначе - как десятичное. Нулевое или отсутствующее n воспринимается
как "очень много"; эта возможность полезна при дополнении цепочки2 до
длины цепочки1.
Обратный слэш можно использовать для задания управляющих символов
( '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v' ). Кроме того, \ обозначает код
символа, если за ним идут одна, две или три восьмеричные цифры.
Следующая команда (см.
листинг 6.36) помещает список всех f1,
по одному на строку, в файл f2 (под
tr -cs '[:alpha:]' '[\n*]' < f1 > f2
Команда, показанная в листинге 6.37, переводит большие буквы в малые, попутно сжимая последовательности одинаковых (без учета регистра) букв.
tr -s '[:upper:]' '[:lower:]'
Служебная программа uniq
uniq [-c | -d | -u] [-f число] [-s число]
[входной_файл [выходной_файл]]
позволяет сократить до одной подряд идущие одинаковые строки (сделать
одинаковые строки файла смежными можно с помощью утилиты sort ). Опции
предоставляют дополнительный сервис.
-c
Перед каждой выходной строкой помещать ее кратность во входном файле.
-d
Подавить вывод неповторяющихся строк.
-f число
При сравнении строк игнорировать заданное число начальных [[:blank:]]*[^[:blank:]]*
-s число
При сравнении строк игнорировать заданное число начальных символов. При
совместном использовании опций -f и -c игнорируется указанное число символов,
идущих после заданного числа
-u
Подавить вывод строк, повторявшихся во входном файле.
В качестве примера употребления утилиты uniq приведем конвейер,
позволяющий найти десять самых употребительных заголовочных файлов среди
включаемых в стандартные заголовочные файлы, расположенные в /usr/include и его
find /usr/include -name '*.h' -exec cat
{} \; | tr -d '[:blank:]' | \
grep -E -e '^#include(<.*>|".*")'
| sort | uniq -dc | sort -r | head
977 #include"nsISupports.h" 315 #include<glib.h> 201 #include<gdk/gdk.h> 167 #include<glibmm.h> 160 #include<features.h> 154 #include<glib-object.h> 144 #include"nsCOMPtr.h" 139 #include<sys/types.h> 139 #include<glibmm/class.h> 135 #include"nscore.h"
Служебная программа cut
cut -b список [-n] [файл ...]
cut -c список [файл ...]
cut -f список [-d разделитель]
[-s] [файл ...]
используется для выборки байт (опция -b ), символов ( -c ) либо
ограниченных разделителями -f ) с заданными списком номерами из строк исходных
файлов, их конкатенации и выдачи на стандартный вывод. Если применить
терминологию реляционных баз данных, cut выполняет
операцию
Список, являющийся -b, -c и -f, задается как
последовательность разделенных запятыми или пробелами положительных чисел или
диапазонов (с естественными умолчаниями, когда границы опущены). Опция -d
определяет разделитель -n предписывает не разрывать (многобайтные) символы, опция -s в
сочетании с -f подавляет вывод строк, в которых не оказалось символов-разделителей (по
умолчанию такие строки копируются на стандартный вывод без изменений).
Пример. Чтобы выделить из базы данных пользователей входные имена и идентификаторы, можно воспользоваться командой, показанной в листинге 6.40. Начальный фрагмент возможного результата приведен в листинге 6.41.
cut -d : -f 1,3 /etc/passwd
root:0 bin:1 daemon:2 adm:3 lp:4 sync:5 . . .
Служебная программа paste
paste [-s] [-d список] файл ...
в терминологии реляционных баз данных осуществляет -s конкатенируются строки
каждого из исходных файлов. Во всех случаях строки склеиваются посредством
символа табуляции (по умолчанию) или символов из списка - аргумента
опции -d. Список этих символов рассматривается как кольцевой, т. е. будучи
исчерпан, он используется повторно. Сочетание \0 в нем трактуется как пустая
В качестве имени исходного файла может быть задан минус, что означает стандартный ввод. Если минус употреблен многократно, то стандартный ввод читается построчно, циклически по именам - минусам. Любопытно отметить, что стандарт POSIX-2001 предписывает реализациям поддерживать обработку не менее двенадцати исходных файлов.
Рассмотрим несколько примеров. Для выдачи в четыре
ls | paste - - - -
Для попарного
paste -s -d "\0\n" f.txt
Если файл не подпадает под определение текстового из-за чрезмерно длинных
строк, утилитой cut можно выделить начальные байты, поместив "хвосты" строк
в другой файл. В дальнейшем из двух полученных файлов с помощью
служебной программы paste можно воссоздать исходный (см.
листинг 6.44).
cut -b 1-80 -n f > f1.txt cut -b 81- -n f > f2 . . . paste -d '\0' f1.txt f2 > f3
Еще один join - выдает на стандартный
вывод результат файла1 и файла2:
join [-a номер_файла | -v номер_файла] [-e цепочка] [-o список] [-t символ] [-1 номер_поля] [-2 номер_поля] файл1 файл2
Отношения файл1 и файл2 должны быть
Результат операции составляют строки, по одной для каждой пары из отношений файл1 и файл2, имеющих одинаковые файл1, затем
остатка строки отношения файл2.
Как правило,
Допустимы следующие опции.
-a номер_файла
В дополнение к обычному выводу выдать строку для каждой непарной строки из файла с указанным номером (1 или 2).
-e цепочка
Заменить пустые -o
заданной
-o список
Составлять выходные строки из номер_файла.номер_поля или
-t символ
Использовать символ в качестве разделителя. Каждое вхождение символа в строку значимо. Указанный символ используется как разделитель и при вводе, и при выводе.
-v номер_файла
Вместо подразумеваемого вывода выдавать только непарные строки из файла с указанным номером (1 или 2).
-1 номер_поля
Производить соединение по файла1 с
заданным номером.
-2 номер_поля
Производить соединение по файла2 с заданным номером.
Рассмотрим примеры. Командная строка (см.
листинг 6.45) выполняет соединение
баз данных пользователей и групп,
join -1 4 -2 3 -o 1.1,2.1,1.6 -t :
passwd.sorted group.sorted
halt:root:/sbin operator:root:/root root:root:/root shutdown:root:/sbin sync:root:/sbin bin:bin:/bin daemon:daemon:/sbin . . .
Пусть имеется два упорядоченных по алфавиту справочника: номера телефонов
и адреса электронной почты (см.
листинг 6.47). Предполагается, что в
качестве разделителя
Имя Номер телефона Иван 123-4567 Петр 123-5678 Яков 123-6789 Имя Адрес электронной почты Иван ivan123@mail.ru Олег oleg@yahoo.com Яков yak@yandex.ru
join -t '<tab>' -a 1 -a 2 -e '---------'
-o 0,1.2,2.2 phone.txt email.txt
Имя Номер телефона Адрес электронной почты Иван 123-45-67 ivan123@mail.ru Олег --------- oleg@yahoo.com Петр 123-56-78 --------- Яков 123-67-89 yak@yandex.ru
Читателю предлагается самостоятельно выбрать правильный способ задания
символа табуляции в качестве -t служебной программы join, а также объяснить, зачем нужен пробел в начале
Обработка opendir()
(см. листинг 6.50).
#include <dirent.h> DIR *opendir (const char *dirname);
После открытия текущим становится первый rewinddir() (см. листинг 6.51).
#include <dirent.h> void rewinddir (DIR *dirp);
Чтение readdir()
(см. листинг 6.52),
которая возвращает указатель на структуру, представляющую текущий errno перед
вызовом readdir(), а затем, если
результат равен NULL, проанализировать это значение.
#include <dirent.h> struct dirent *readdir (DIR *dirp);
Согласно стандарту POSIX-2001, структура dirent содержит по крайней мере одно
char d_name []; /* Имя файла */
В качестве необязательного описано еще одно
ino_t d_ino; /* Порядковый номер файла */
Если
Следует учитывать, что указатель, возвращаемый функцией readdir(), может
ссылаться на область памяти, перезаписываемую другими обращениями к readdir()
с тем же значением аргумента dirp. Кроме того, нужно помнить и о том, что
содержимое читаемого
После завершения работы с closedir() (см. листинг 6.53),
возвращающей
#include <dirent.h> int closedir (DIR *dirp);
Нередко fnmatch() (см. листинг 6.54).
#include <fnmatch.h> int fnmatch (const char *file_pattern, const char *file_name, int flags);
На процесс file_name
с file_pattern влияют следующие флаги:
FNM_PATHNAME
Трактовать имя file_name как маршрутное. Символу / в имени должен
явным образом сопоставляться этот же символ в шаблоне (а не ?
или / трактуется наравне с другими.
FNM_NOESCAPE
При наличии этого флага символ \ трактуется наравне с другими. В противном
случае он играет экранирующую роль.
FNM_PERIOD
Если этот флаг установлен, точка в начале имени файла должна сопоставляться с точкой в шаблоне. Иначе точка в начале имени сопоставляется на общих основаниях.
В случае успешного fnmatch() возвращает ноль,
при неудаче результат равен FNM_NOMATCH, в случае ошибки возвращается
другое ненулевое значение.
В качестве примера употребления описанных функций рассмотрим
программу, которая выводит имена файлов текущего
#include <dirent.h>
#include <fnmatch.h>
#include <errno.h>
#include <stdio.h>
/* Программа сопоставляет имена файлов текущего каталога с заданными шаблонами */
#define SEARCH_DIR "."
static void match_names (DIR *dirp, const char *pattern) {
struct dirent *dp;
rewinddir (dirp);
while (errno = 0, (dp = readdir (dirp)) != NULL) {
if (fnmatch (pattern, dp->d_name, FNM_PERIOD) == 0) {
(void) printf (" %s\n", dp->d_name);
}
}
if (errno != 0) {
perror ("Ошибка при чтении каталога " SEARCH_DIR);
}
}
int main (int argc, char *argv []) {
DIR *dirp;
int i;
if ((dirp = opendir (SEARCH_DIR)) == NULL) {
perror ("Ошибка при открытии каталога " SEARCH_DIR);
return (-1);
}
for (i = 1; i < argc; i++) {
(void) printf ("Файлы каталога " SEARCH_DIR ", удовлетворяющие шаблону %s\n", argv [i]);
match_names (dirp, argv [i]);
}
return (closedir (dirp));
}
Справедливости ради нужно отметить, что приведенный пример носит искусственный
характер, поскольку для glob()
(см. листинг 6.56).
#include <glob.h> int glob (const char *restrict file_pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *restrict pglob); void globfree (glob_t *pglob);
Функция glob() сопоставляет все доступные маршрутные имена с file_pattern и генерирует список успешно glob() возвращает в структуре типа glob_t, содержащей,
согласно стандарту, по крайней мере следующие
size_t gl_pathc; /* Число успешно сопоставленных маршрутных имен */ char **gl_pathv; /* Массив указателей на успешно сопоставленные маршрутные имена */ size_t gl_offs; /* Число элементов, которые нужно зарезерви- ровать в начале массива gl_pathv */
Структура, на которую указывает аргумент pglob, должна создаваться
приложением. Другие области памяти, в том числе массив gl_pathv, резервируются
функцией glob() по мере необходимости и освобождаются после обращения к globfree() с тем же значением pglob.
Работой функции glob() можно управлять с помощью следующих флагов.
GLOB_APPEND
Добавлять вновь glob().
GLOB_DOOFFS
Принимать во внимание gl_offs.
Если этот флаг установлен, то pglob->gl_pathv будет указывать
на pglob->gl_offs пустых указателей, за которыми
следуют pglob->gl_pathc указателей на маршрутные имена и завершающий пустой
указатель.
GLOB_ERR
Завершать работу по достижении glob() продолжает процесс
GLOB_MARK
Добавлять символ / после имен успешно
GLOB_NOCHECK
При отсутствии успешно
GLOB_NOESCAPE
Запретить экранирование символом \.
GLOB_NOSORT
Не
Если в процессе своей работы функция glob() достигает errfunc отличен от пустого
указателя, то glob() вызывает (*errfunc ()) с двумя аргументами:
"проблемным" маршрутным именем и соответствующим значением errno.
Если этот вызов возвращает значение, отличное от нуля, или если установлен флаг GLOB_ERR, pglob->gl_pathc и pglob->gl_pathv устанавливаются в соответствии с уже обработанными маршрутами, а
результат вызова функции glob() полагается равным GLOB_ABORTED (при
нормальном завершении возвращается 0).
Перепишем программу, которая выводит имена файлов, удовлетворяющие заданным в
командной строке шаблонам, воспользовавшись функцией glob()
(см. листинг 6.57).
#include <glob.h>
#include <errno.h>
#include <stdio.h>
/* Программа выводит маршрутные имена, сгенерированные по заданным шаблонам */
static int errfunc (const char *epath, int eerrno) {
fprintf (stderr, "Ошибка при обработке каталога %s: ", epath);
errno = eerrno;
perror (NULL);
return (0);
}
int main (int argc, char *argv []) {
glob_t gl_buf;
int i;
for (i = 1; i < argc; i++) {
(void) glob (argv [i], ((i == 1) ?
}
(void) printf ("Маршрутные имена, сгенерированные по заданным шаблонам:\n");
for (i = 0; (unsigned) i < gl_buf.gl_pathc; i++) {
(void) printf ("%s\n", gl_buf.gl_pathv [i]);
}
globfree (gl_buf);
return (0);
}
Выше, при описании языка shell, мы рассматривали служебную программу . Ее логическим дополнением является утилита dirname:
dirname цепочка_символов
Она выдает на стандартный вывод имя dirname как
В качестве примера использования утилиты dirname приведем фрагмент
командного файла, выполняемого при загрузке ОС Linux
(см. листинг 6.58).
if [ "`dirname $RAW`" = "/dev/raw" -a -f /dev/raw ]; then echo $" Please correct your /etc/sysconfig/rawdevices:" echo $" rawdevices are now located in the directory /dev/raw/ " echo $" If the command 'raw' still refers to /dev/raw as a file." echo $" you'll have to upgrade your util-linux package" exit fi
Совместное использование утилит и dirname иллюстрирует
листинг 6.59.
Это командный файл с одним аргументом - маршрутным именем
компилируемого C-файла, которое может быть задано как с расширением .c,
так и без него.
gcc -Wall -W -pedantic -o $(basename "$1" .c)
$(dirname "$1")/$(basename "$1" .c).c
Согласно определению, данному в стандарте POSIX-2001, текстовым называется
файл, символы которого объединены в строки длиной не более {LINE_MAX}, не
содержащие нулевого символа.
Вероятно, простейшей операцией с файлами (не обязательно текстовыми) является их выдача на стандартный вывод, что обеспечивается посредством утилиты
cat [-u] [файл ...]
Несмотря на внешнюю простоту, применение служебной программы cat сопряжено с
рядом тонкостей. Во-первых, опция -u предписывает передавать на
стандартный вывод байты из входных файлов без задержек, это означает, в частности,
отмену буферизации стандартного вывода. Во-вторых, если не указаны
исходные файлы или в качестве аргумента задан знак минус, используется
стандартный ввод. Минус может фигурировать в командной строке несколько раз,
стандартный ввод не закрывается и не переоткрывается. Например, допустимы
команды, показанные в листинге 6.1, причем первая
обеспечит ввод двух интерактивных вставок, а вторая эквивалентна третьей (читателю
предлагается самостоятельно объяснить данный факт).
cat f1.txt - f2.txt - f3.txt cat g1.txt - g2.txt - g3.txt < input.txt cat g1.txt - g2.txt /dev/null g3.txt < input.txt cat f1.txt f2.txt > f1.txt
В-третьих, нужно учитывать особенности cat выдает результат f1.txt.
Для
more [опция ...] [файл ...]
Она разбивает вывод на
Программа more - довольно мощный cat, а из
опций выделим три.
-n число
Задает число строк, выдаваемых на экран.
-p команды more
Команды more выполняются после входа в очередной файл и вывода его первого
экрана. Это может быть, к примеру, команда поиска.
-s
Сжимать последовательные пустые строки в одну.
Утилита more часто используется как заключительное звено конвейеров для удобного просмотра результатов.
Для
od [опция ...] [файл ...]
Она выдает на стандартный вывод содержимое исходных файлов в формате,
заданном пользователем, а также в виде блоков, каждый из которых в простейшем (и
наиболее употребительном) случае состоит из шестнадцати байт и занимает при
выводе одну строку. В начале подобной строки располагается смещение блока от
начала файла, затем следует содержимое блока. С помощью -A
можно задать основание системы счисления для смещений ( d -
десятичное, o - восьмеричное, x - шестнадцатеричное, n - не выдавать смещение).
Формат выдачи содержимого определяется -t. Помимо
перечисленных типов могут быть заданы a
( c (символы), f (вещественные числа), u (беззнаковые десятичные). За спецификациями d, f, o, u и x
может следовать десятичное число - количество байт в одном значении
заданного типа; за спецификацией f - символы F, D или L, указывающие тип
вещественных чисел ( float, double или long double,
соответственно), а за спецификациями d, o, u, x - спецификаторы целочисленного типа C ( char ), S ( short ), I ( int ) или L ( long ).
Рассмотрим пример. Пусть файл ascii.tab содержит байты от
od -A x -t a ascii.tab
000000 nul soh stx etx eot enq ack bel bs ht nl vt ff cr so si
000010 dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us
000020 sp ! " # $ % ' ( ) * + , - . /
000030 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
000040 @ A B C D E F G H I J K L M N O
000050 P Q R S T U V W X Y Z [ \ ] ^ _
000060 ` a b c d e f g h i j k l m n o
000070 p q r s t u v w x y z { | } ~ del
000080
Полезная возможность - взглянуть на начало файла, чтобы понять, нуждается ли он в более детальном изучении. Эта возможность реализуется служебной программой head:
head [-n число] [файл ...]
Утилита head копирует на стандартный вывод указанное число (по умолчанию
- 10) начальных строк исходных файлов (или весь файл, если он слишком
короткий).
"Симметричная" служебная программа - tail
tail [-f] [-c число | -n число] [файл]
выдает на стандартный вывод конец исходного файла, начиная с указанного
места. Если задана опция -c, единицей измерения является байт, если -n
- строка. Числовой
Опция -f полезна для слежения за растущими файлами, в которые пишет
какой-либо другой процесс. При наличии этой опции утилита tail не завершается по
достижении конца файла, но ждет появления новых данных и выводит их.
Рассмотрим примеры. Команда
tail -f f1
выдаст последние десять строк файла f1, за которыми последуют строки,
добавленные к файлу f1 в промежуток времени между запуском и терминированием
утилиты tail.
В качестве примера совместного использования служебных программ head
и tail приведем фрагмент одного из командных файлов ОС Linux (см.
листинг 6.4).
echo "Reloading automounter: checking\ for changes ... " TMP=/var/run/autofs.tmp getmounts > $TMP for i in /var/run/autofs.*.pid do pid=`head -n 1 $i 2>/dev/null` [ "$pid" = "" ] continue command=`tail -n +2 $i` if ! grep -q "^$command" $TMP then echo "Stopping automounter: $command" kill -USR2 $pid fi done rm -f $TMP
Отметим, что здесь утилиты head и tail делят исходный файл
"по-братски": первой достается первая строка, второй - все остальные.
Служебная программа pr
pr [+номер_страницы] [-число_столбцов] [-adFmrt] [-e[символ][число]] [-h заголовок] [-i[символ][число]] [-l число_строк] [-n[символ][ширина]] [-o отступ] [-s[символ]] [-w ширина] [файл ...]
является
Утилита pr обрабатывает следующие аргументы командной строки.
+номер_страницы
Начать вывод со
-число_столбцов
Вывод в заданное число -e и -i.
Этот аргумент несовместим с опцией -m.
-a
Выдача в несколько
-d
Выдача через строку.
-e[символ][число]
Установка табуляции через заданное число позиций, начиная с первой. Символы табуляции во входном файле развертываются в соответствующее количество пробелов. Если задан любой нецифровой символ, он трактуется как символ табуляции во входном файле.
-F
Применять символы перехода к новой
-h заголовок
Использовать заданный
-i[символ][число]
При выводе, где это возможно, последовательности пробельных символов заменяются символами табуляции, при условии, что табуляции установлены через заданное число позиций, начиная с первой. Если задан любой нецифровой символ, он выводится в качестве символа табуляции.
-l число_строк
Установка длины
-m
-n[символ][ширина]
Производится нумерация строк. Под номер отводится поле заданной ширины (по умолчанию - 5). Если задан любой нецифровой символ, то он присоединяется к номеру строки, отделяя ее от последующего текста (подразумеваемым значением является символ табуляции).
-o отступ
Установка
-p
Пауза перед выдачей каждой pr включит звонок и будет ждать нажатия клавиши возврата каретки).
-r
Подавление диагностических сообщений при ошибках открытия файлов.
-s[символ]
Разделение
-t
Подавление выдачи пятистрочного идентифицирующего
-w ширина
Установка ширины строки (по умолчанию - 72 позиции). Эта опция действует
только при печати в несколько
В качестве примера использования служебной программы pr приведем
конвейер, позволяющий получить пронумерованный список всех файлов текущего
ls -a | pr -2 -a -l 24 -n' '3 -h "Список\ файлов каталога $(pwd)"
Начальный фрагмент результата может выглядеть так, как показано в листинге 6.5.
2003-10-17 17:24 Список файлов каталога /var/tmp Page 1 1 . 2 .. 3 Blank.ReS 4 Make45.ReS 5 Make46.ReS 6 from_cvs 7 gcc-20032204 8 gcc-3.4-16-jun-2003 9 htdocs 10 rpm-tmp.29785 . . .
Для подсчета числа символов,
wc [-c | -m] [-w] [-l] файл ...
Опция -c предписывает подсчитывать байты, -m - символы, -w - -l
- строки. По умолчанию подсчитываются символы,
Рассмотрим пример. Предположим, что результаты, показанные в
листинге 6.3,
сохранены в файле ascii.od. Тогда команда, приведенная в
листинге 6.6, выдаст
результат, показанный в листинге 6.7.
wc ascii.od
9 137 575 ascii.od
Иными словами, в указанном файле 575 символов, 137 слов, расположенных на 9 строках.
Служебная программа sort
sort [-m] [-o выходной_файл] [-bdfinru] [-t символ] [-k определение_ключа] ... [файл ...] sort -c [-bdfinru] [-t символ] [-k определение_ключа] [файл]
в зависимости от заданных опций выполняет одно из трех возможных действий:
При упорядочении используется один или несколько
Следующие опции управляют порядком работы утилиты sort.
-c
Проверить, является ли (единственный) исходный файл уже
-m
-o выходной_файл
Результат направляется не на стандартный вывод, а в выходной_файл, который
может совпадать с одним из исходных.
-u
Опция уникальности: из всех совпадающих строк выводить только одну, при
наличии опции -c контролировать отсутствие строк с совпадающими
Следующие опции изменяют подразумеваемый способ сравнения. Если они
употреблены независимо от определения
-d
"Словарный" порядок: при сравнении являются значимыми только буквы, цифры и пробельные символы.
-f
При сравнении преобразовывать малые буквы в большие.
-i
При сравнении игнорировать непечатные символы.
-n
Числовое сравнение. Ограничить
-r
Заменить результат сравнения на противоположный.
Следующие опции изменяют трактовку
-b
Игнорировать начальные пробельные символы при определении начала и конца -b указана перед первой опцией -k, она воздействует на все
ключи, снабженные опцией -k.
-t символ
Использовать заданный символ как -t подразумеваемыми разделителями становятся
пробельные символы, точнее, максимальная непустая последовательность таких
символов, а в поле включаются предшествующие ему разделители.
-k. Определение ключа имеет
следующий формат:
начало_поля[тип][,конец_поля[тип]]
Ключевое поле охватывает все позиции - от начальной до конечной, которые задаются, соответственно, как
номер_поля[.первый_символ] номер_поля[.последний_символ]
Тип - это один из модификаторов b, d, f, i, n, r.
Модификатор b ведет себя аналогично опции -b,
но применяется только к той границе ключа, после
которой он указан. Остальные модификаторы также аналогичны одноименным
опциям, но воздействуют на ключ в целом.
Если указано несколько -k ), то более поздние используются только в случае равенства более ранних. Если
значения
Приведем примеры использования служебной программы sort. Автор хранит данные
о собственном кровяном давлении в виде файла pp.txt, содержащего пять
12.05.2000 17:30 200 125 120 15.05.2000 17:00 130 80 70 17.05.2000 10:30 150 90 70 17.05.2000 21:45 154 99 74 19.05.2000 10:05 158 83 89 21.05.2000 21:00 161 104 64 22.05.2000 21:00 147 104 69 . . .
sort -r -k 3,3 pp.txt
12.05.2000 17:30 200 125 120 18.11.2000 19:30 172 107 68 04.07.2002 09:00 170 98 85 30.10.2001 13:00 168 94 88 27.12.2000 20:30 166 98 69 23.05.2002 10:00 166 104 56 22.05.2002 10:00 166 103 57 23.10.2001 11:00 165 88 88 . . .
Если
# Первый вариант - ключ сортировки покрывает # несколько полей sort -r -k 3,5 pp.txt # Второй вариант - используется несколько # ключей сортировки # sort -n -r -k 3,3 -k 4,4 -k 5,5 pp.txt
12.05.2000 17:30 200 125 120 18.11.2000 19:30 172 107 68 04.07.2002 09:00 170 98 85 30.10.2001 13:00 168 94 88 23.05.2002 10:00 166 104 56 22.05.2002 10:00 166 103 57 27.12.2000 20:30 166 98 69 23.10.2001 11:00 165 88 88 . . .
Предположим теперь, что данные о давлении и пульсе разбиты по годам и в уже pp2000.sorted, pp2001.sorted и т.д. Для их
# Первый вариант слияния файлов
# sort -m -o pp.sorted -n -r -k 3,3 -k 4,4
# -k 5,5 pp2*.sorted
# Второй вариант слияния файлов
> pp.sorted
for f in pp2*.sorted
do
sort -m -o pp.sorted -n -r -k 3,3\
-k 4,4 -k 5,5 $f pp.sorted
done
Проверить правильность
name=pp.sorted
if sort -c -r -n -k 3,3 -k 4,4 -k 5,5 $name
then
echo Данные в файле $name отсортированы\
верно
elif
echo Данные в файле $name отсортированы\
неверно
fi
Содержимое файлов f1 и f2 сортирует команда (см. листинг 6.15) , применяющая в качестве ключа второй непробельный символ второго поля.
sort -k 2.2b,2.2b f1 f2
sort -t ':' -k 3,3n /etc/passwd
Выдать содержимое уже f.sorted, выводя лишь первую
из строк с одинаковыми третьими полями, поможет комбинация опций -m и -u
(см. листинг 6.17).
sort -um -k 3.1,3 f.sorted
В ситуациях, когда есть две версии текста - "правильная" и
"неправильная" (например, исходные тексты работающей и неработающей программ),
полезно понять, чем они отличаются. Для этого предназначена служебная
программа diff:
diff [-c | -e | -f | -C число] [-br]
файл1 файл2
Утилита diff сравнивает содержимое исходных файлов и выдает на стандартный
вывод список изменений, которые необходимо произвести, чтобы
преобразовать файл1 в файл2. Она поддерживает следующие опции.
-b
Игнорировать пробельные символы в конце строк; остальные
-c
Производить вывод в формате, обеспечивающем три строки контекста.
-C число
Производить вывод в формате, обеспечивающем заданное число строк контекста.
-e
Производить вывод в формате, пригодном для подачи на вход редактора ed и
преобразования файла1 в файл2.
-f
Производить вывод в альтернативном формате, напоминающем -e, но в обратном
порядке и не предназначенном для подачи на вход редактора ed.
-r
Если файл1 и файл2 представляют собой diff рекурсивно к одноименным и однотипным обычным файлам и
В качестве примера использования служебной программы diff сравним две
версии бинарных утилит (см. листинг 6.18).
Начальный фрагмент результата
показан в листинге 6.19.
Видно, что различия, по сути, сводятся к добавлению
новых файлов.
diff -r binutils-2_14 binutils-2_14-branch
diff -r binutils-2_14/bfd/version.h binutils-2_14-branch/bfd/version.h 1c1 < #define BFD_VERSION_DATE 20030612 --- > #define BFD_VERSION_DATE 20031007 Only in binutils-2_14-branch/binutils: ChangeLog Only in binutils-2_14-branch/binutils: arlex.c Only in binutils-2_14-branch/binutils: deflex.c Only in binutils-2_14-branch/binutils: rclex.c Only in binutils-2_14-branch/binutils: syslex.c Only in binutils-2_14-branch: config.guess Only in binutils-2_14-branch/gas: ChangeLog Only in binutils-2_14-branch/gas/config: tc-ns32k.c Only in binutils-2_14-branch/gas: configure Only in binutils-2_14-branch/gas: configure.in Only in binutils-2_14-branch/gas: itbl-lex.c . . .
Если нужно проверить два файла на совпадение, предпочтительнее
воспользоваться не утилитой diff, а более простой и быстрой служебной
программой cmp:
cmp [-l | -s] файл1 файл2
По умолчанию cmp выдает на стандартный вывод номера байта и строки, где
встретилось первое отличие. Опция -l предписывает выдавать все отличия в виде
номеров и содержимого (восьмеричного) байт. По опции -s отличия не выдаются,
возвращается лишь соответствующий код завершения (0 - файлы совпадают, 1 -
файлы различаются, больше единицы - зафиксирована ошибка).
Если в продолжение примера с утилитой diff сравнить две версии файла version.h посредством cmp
(см. листинг 6.20), результат будет выглядеть так,
как показано в листинге 6.21.
cmp -l binutils-2_14/bfd/version.h\ binutils-2_14-branch/bfd/version.h
30 60 61 31 66 60 32 61 60 33 62 67
Еще одно средство выявления различий (и, кроме того, совпадений)
текстовых файлов - служебная программа comm:
comm [-123] файл1 файл2
Она читает файл1 и файл2 (их содержимое должно быть
Опции -1, -2 или -3
подавляют вывод соответствующих comm -12 выводит строки, общие для обоих файлов, comm -23 -
имеющиеся только в файле1, comm -123 не выводит ничего.
В стандарте POSIX-2001 приведен следующий пример использования
служебной программы comm. Пусть файл xcu содержит - аналогичный список для
спецификации X/Open Portability Guide, Issue 3, а файл svid89 представляет собой
отсортированный список утилит из System V
comm -12 xpg3 svid89 | comm -23 - xcu
Для
cksum [файл ...]
Для каждого файла - аргумента она выдает на стандартный вывод
подсчитанную по стандарту ISO/IEC 8802-3:1996 (Ethernet)
Применение утилиты cksum - полезный элемент оформления поставляемых
приложений.
Понятие
Когда хотят подчеркнуть составной характер
Стандарт накладывает на сложность (полных) РВ единственное ограничение: реализация должна поддерживать любое РВ, длина которого не превышает 256 байт.
Оговаривается, что при наличии альтернатив выбирается самая левая из возможных цепочек, имеющая к тому же максимальную длину.
Различают
Минимальным элементом
\ следует любой . [ \Эти символы имеют специальный смысл, за исключением случая, когда они заключены в квадратные скобки.
*Символ имеет специальный смысл, если он не заключен в квадратные скобки или не является первым символом
^Символ имеет специальный смысл в начале полного
$Символ имеет специальный смысл в конце полного
[ ]
представляет собой ^,
то Внутри квадратных скобок можно использовать также конструкции, описываемые ниже.
-. Например, [0-9]
эквивалентно [0123456789]. Минус теряет свой специальный смысл, если он стоит в
начале (допустимо после ^ ) или в конце [%--] успешно
сопоставляется со всеми символами от процента до минуса включительно.
Закрывающая квадратная скобка не рассматривается как окончание ^ ).
Таким образом, []a-f]
определяет либо закрывающую квадратную скобку,
либо любой символ от a до f включительно.
Стандарт POSIX-2001 предусматривает поддержку
[:alnum:] [:cntrl:] [:lower:] [:space:] [:alpha:] [:digit:] [:print:] [:upper:] [:blank:] [:graph:] [:punct:] [:xdigit:]
Например, [^[:alnum:]] удовлетворяют символы, отличные от букв и цифр.
В некоторых языках [[.ch.]].
Если определены классы элементов, эквивалентных при алфавитном
сравнении, то подобный класс можно задать, заключив любой его ([= и =]).
Таковы правила построения заключенных в квадратные скобки односимвольных
Построение
\( и \). \n (где n -
цифра от 1 до 9). n, считая от начала полного \(.\)\1 удовлетворяют пары одинаковых символов.\(.*\)\1 удовлетворяют пары стоящих рядом одинаковых
цепочек символов.\{m\}, \{m,\} или \{m,n\} m и n должны
удовлетворять неравенствам^
( $ ( ^\(.*\)\1$
успешно сопоставляется с Операции построения
Опишем отличия
|.| и
имеет низший приоритетa((bc)|d) успешно
сопоставляется и с "abc",
и с "ad". Односимвольные | и заключенные в круглые скобки, трактуются как односимвольные.Таковы правила построения и обработки
Мы приступаем к описанию наиболее употребительных служебных программ и
функций, использующих механизм grep:
grep [-E | -F] [-c | -l | -q] [-insvx]
-e список_шаблонов ...
[-f файл_шаблонов] ... [файл ...]
grep [-E | -F] [-c | -l | -q] [-insvx]
[-e список_шаблонов ...]
-f файл_шаблонов ... [файл ...]
grep [-E | -F] [-c | -l | -q] [-insvx]
список_шаблонов [файл ...]
Она служит для выборки строк исходных файлов, удовлетворяющих хотя бы одному шаблону из заданного списка.
Три приведенные выше варианта вызова служебной программы grep
отличаются способом задания списка шаблонов. В первом случае он является
-e, во втором извлекается из файла шаблонов - аргумента
опции -f, в третьем указывается как самостоятельный аргумент командной
строки, но отдельные элементы этого списка всегда разделяются символами
перевода строки. Опция -e полезна в ситуациях, когда нужно задать шаблон,
начинающийся со знака минус.
По умолчанию шаблоны трактуются как -E предписывает переход к -F означает, что в
качестве шаблонов выступают
Опции -c, -l, -q и -n
влияют на выдачу результатов. По умолчанию на
стандартный вывод выдаются строки исходных файлов, в которых присутствуют
успешно -c предписывает выдавать
только общее число подобных строк, -l - только имена файлов, где
имеются успешно -q - только код завершения (0 - есть
успешно -n требует ставить ее номер в исходном файле
перед каждой выводимой строкой (нумерация строк начинается с 1).
Опции -i, -v и -x воздействуют на процесс -i предписывает не
различать при -v - выбирать строки,
не удовлетворяющие ни одному из заданных шаблонов, -x - рассматривать
только строки, все символы которых участвуют в успешном
Опция -s подавляет выдачу диагностических сообщений о том, что исходный
файл не существует или не доступен на чтение.
Отметим, что опции -F и -q, каждая по-своему,
ускоряют работу служебной
программы grep: -F упрощает -q позволяет завершить -q и -s позволяет также более свободно
задавать исходные файлы, не заботясь об их существовании и доступности.
Рассмотрим примеры использования утилиты grep. Для выборки пустых строк из файла
стандартного ввода пригодны два шаблона:
grep ^$ grep -v .
Если нужно выбрать строки, имеющие вид abc или def, можно воспользоваться одной из трех команд:
grep -E '^abc$|^def$' grep -F -x 'abc def'
И наконец, пусть в файлах с исходными текстами Фортран-программ требуется найти все строки, содержащие вызовы подпрограмм и не являющиеся комментариями. Для такой выборки "в первом приближении" (учитывая нерегулярний синтаксис Фортрана) подойдет следующая команда:
grep -i '^[^C].* CALL ' *.for
В командных файлах для обработки текстов часто используется sed:
sed [-n] сценарий [файл ...]
sed [-n] [-e сценарий] ...
[-f файл_сценария] ... [файл ...]
Редактор sed читает указанные текстовые файлы (по умолчанию -
стандартный ввод), выполняет редактирование в соответствии с командами -e и -f
аналогичен утилите grep. Опция -n подавляет подразумеваемый вывод и
предписывает выдавать только явно отобранные строки.
Сценарий для sed состоит из редактирующих команд (каждая на отдельной строке),
имеющих следующий формат:
[адрес [, адрес]] функция [аргумент ...]
Функция имеет здесь однобуквенное обозначение.
В нормальном режиме sed циклически выполняет следующие
D.-n, копирует буфер на стандартный вывод, добавив
в конце перевод строки. Очищает буфер.Некоторые команды используют хранилище, чтобы запомнить весь буфер или его часть для последующего применения.
Адрес в редактирующей команде sed - это либо десятичное число,
означающее номер входной строки в совокупности входных файлов, либо символ $,
который обозначает последнюю входную строку, либо /базовое_регулярное_выражение/.
Командная строка без адреса применима к любому буферу, командная строка с одним адресом - к буферу с соответствующим адресом, командная строка с двумя адресами - к буферам с адресами в диапазоне от первого до второго включительно; затем процесс повторяется, начиная с первой строки вслед за выбранным диапазоном.
Перечислим команды редактора sed. В скобках указывается максимальное число
допустимых адресов для каждой функции.
Аргумент текст состоит из одной или более строк. Все строки, кроме последней,
заканчиваются на \, чтобы экранировать символ перевода строки.
(2){ функция
функция
...
}
Выполнить заданную последовательность функций.
(1)a\ текст
Добавить. Вывести текст перед чтением следующей входной строки.
(2)b [метка]
Перейти к команде :, содержащей метку.
Если метка пуста, перейти на конец
(2)c\ текст
Заменить. Удалить содержимое буфера. При 0 или 1 адресе или в конце двухадресного диапазона вывести текст. Начать новый цикл.
(2)d
Удалить содержимое буфера. Начать новый цикл.
(2)D
Удалить начало буфера до первого перевода строки. Начать новый цикл.
(2)g
Заменить содержимое буфера содержимым хранилища.
(2)G
Добавить к содержимому буфера содержимое хранилища.
(2)h
Заменить содержимое хранилища содержимым буфера.
(2)H
Добавить к содержимому хранилища содержимое буфера.
(1)i\ текст
Вставить. Вывести текст.
(2)l
Вывести буфер, заменяя непечатные символы на пары символов ASCII и разбивая длинные строки.
(2)n
Скопировать буфер на стандартный вывод, если подразумеваемый вывод не подавлен.
Заменить содержимое буфера на следующую входную строку. Если таковой не
оказалось, завершить выполнение
(2)N
Добавить к буферу следующую входную строку, вставив перед ней символ перевода
строки. (Текущий номер строки изменяется.) Если входных строк больше нет,
завершить выполнение
(2)p
Скопировать буфер на стандартный вывод.
(2)P
Скопировать начальный сегмент буфера (до первого перевода строки) на стандартный вывод.
(1)q
Выйти. Перейти на конец
(2)r ч_файл
Прочитать содержимое ч_файла. Поместить его на стандартный вывод перед чтением
следующей входной строки.
(2)s/БРВ/замена/флаги
Подставить замену вместо фрагментов буфера, отождествленных с
n - заменить n-е вхождение g - заменить все вхождения p - если замена произошла, вывести содержимое буфера;w з_файл - если замена произошла, добавить содержимое буфера к з_файлу.Вместо символа в замене подставляется
(2)t [метка]
Проверить. Перейти к команде :, содержащей метку, если со времени последнего
чтения входной строки или последнего выполнения команды t в буфере
производились подстановки. Если метка пуста, перейти на конец
(2)w з_файл
Записать. Добавить содержимое буфера к з_файлу.
(2)x
Обменять содержимое буфера и хранилища.
(2)y/цепочка1/цепочка2/
Заменить все символы буфера, содержащиеся в цепочке1, на соответствующие
символы цепочки2. Длины цепочек должны совпадать.
(2)! функция
Отрицание. Применить функцию (или группу, если функция начинается с { ) только к
строкам, не соответствующим адресам.
(0): метка
Не делает ничего. Содержит лишь метку, на которую может быть осуществлен переход командами t или b.
(1)=
Вывести в качестве отдельной строки номер текущей строки.
(0)
Пустая команда.
(0)#
#n,
подразумеваемый вывод подавляется (что эквивалентно опции -n в командной строке). В
остальных случаях игнорировать # и остаток строки.
Последовательность символов \n успешно сопоставляется с переводом строки.
Явный символ перевода строки не должен использоваться в
Приведем примеры использования sed. В процессе загрузки
ОС Linux выполняются командные строки, аналогичные показанным в
листинге 6.23.
map=`basename $map | sed -e s/^auto_home/auto.home/ -e s/^auto_mnt/auto.mnt/` cat /etc/auto.master | grep -v '^+' | sed -e '/^#/d' -e '/^$/d'
Первая из них заменяет подчеркивание на точку в именах файлов, обслуживающих
автомонтирование файловых систем, вторая отсеивает строки файла auto.master,
начинающиеся с символа + (это делает grep -v ), комментарии
(строки, начинающиеся символом #) и пустые строки.
Следующий вызов sed (см.
листинг 6.24) сжимает несколько идущих подряд пустых
строк в одну.
sed -n '
p
/^$/ {
# Текущая строка - пустая.
# Добавляем следующие строки к буферу,
# пока он остается пустым.
# Тем самым игнорируются "лишние" пустые
# строки.
:Empty
n
/^$/ b Empty
# Добавленная строка оказалась непустой.
# Выведем ее.
p
}
'
Любопытно сопоставить приведенный нами
sed -n '
# Выведем непустые строки
/./ {
p
d
}
# Выведем одну пустую строку, затем
# проанализируем следующие.
/^$/ p
# Прочитаем следующую строку, отбросим
# оставшийся перевод строки (пустую строку)
# и вернемся к проверке пустой строки.
:Empty
/^$/ {
N
s /.//
b Empty
}
# Выведем непустую строку, затем вернемся к
# поиску первой пустой.
p
'
Еще одно популярное средство обработки текстовых файлов -
служебная программа :
awk [-F РРВ] [-v присваивание] ...
программа [аргумент ...]
awk [-F РРВ] -f программный_файл ...
[-v присваивание] ... [аргумент ...]
Утилита выполняет программы, написанные на одноименном языке
программирования, специально предназначенном для обработки текстов. Программа на
языке представляет собой последовательность шаблонов и
соответствующих
шаблон { действие }
Ввод для делится на обрабатывает ввод построчно. RS. Каждая FS или указав
опцию -F с аргументом - $1, $2,...; $0 - вся входная строка.
Каждая исходная строка сопоставляется с каждым из шаблонов; в случае успеха
выполняются указанные
Действие есть последовательность
if ( условие ) оператор [ else оператор ];while ( условие ) оператор;for ( выражение; условие; выражение ) оператор;break;continue;{ [ оператор ] ... };переменная = выражение # оператор присваивания;print [ список_выражений ] [> выражение ];printf формат [, список_выражений ] [> выражение ];next # пропустить оставшиеся шаблоны и перейти к следующей строке;exit # пропустить оставшиеся строки.список_выражений означает всю строку. +, -, *, /, %, ^ (возведение в степень) и
конкатенации (обозначается пробелом). В них также можно использовать операции из
языка C: ++, --, +=, -=, *=, /=, %=, ^=, ?: (условное x[i] ) или
print выдает свои аргументы на
стандартный вывод (или в файл, если присутствует часть >выражение), разделяя их текущим printf делает то же, но под управлением формата.
Язык содержит большое число
Математические функции atan2 (y, x), cos (x), sin (x), exp (x), log (x), sqrt (x) не
нуждаются в пояснениях. Функция int (x) отбрасывает дробную часть своего
аргумента, rand () возвращает псевдослучайное число в диапазоне от
В число функций, оперирующих gsub (РРВ, замена[, цепочка]) и sub (РРВ, замена[, цепочка])
- соответственно,
глобальная и однократная $0 или s редактора sed и ее флагом g; index
( length [([цепочка])] -
вычисление длины $ ); match> (цепочка, РРВ) - поиск вхождения RSTART и RLENGTH (см. далее); split (цепочка, массив[, РРВ-разделитель]) - расщепление sprintf (формат, выражение, выражение, ...) - формирование substr (цепочка, m[, n]) - выделение
n-символьной m ; tolower (цепочка) - приведение
к строчным буквам; toupper (цепочка) - приведение к прописным буквам.
В языке имеются также группа функций ввода/вывода и функции общего
назначения. Функция close (выражение) закрывает файл или канал, поименованный
заданным getline [переменная]
обеспечивает чтение записи из
текущего входного файла (возможно использование конвейера вида | getline [переменная] и перенаправление ввода getline [переменная] < выражение ), system (выражение) - выполнение команды, заданной
Язык допускает определение пользовательских функций, для чего служит конструкция
function имя_функции ([аргумент, ...])
{ операторы }
Шаблон в языке - это произвольная логическая комбинация,
составленная с помощью операций !, ||,
и скобок из /. Отдельное
выражение опер_сопост РРВ выражение опер_сравн выражение
Здесь опер_сравн - любая из шести операций сравнения языка C, опер_сопост - это ~ (успешно сопоставляется)
или !~ (не сопоставляется).
Условие - арифметическое
Для выполнения каких-либо BEGIN и END.
Шаблон BEGIN следует указывать первым, END - последним.
Присваивания, заданные в командной строке с помощью опции -v, выполняются до начала
интерпретации BEGIN ). Например, для использования символа c в качестве -v 'FS = c'.
В командной строке можно указать также аргументы двух типов -
имена файлов с исходными данными и присваивания. Последние выполняются
непосредственно перед чтением указанного следующим исходного файла. В частности,
присваивания, заданные перед первым аргументом-файлом выполняются после BEGIN, а те, что расположены в конце
командной строки, - перед END. Если в
командной строке нет аргументов-файлов, присваивания выполняются перед
обработкой стандартного ввода.
Перечислим
ARGC
ARGV
Массив аргументов командной строки , исключая опции и программы.
CONVFMT
Формат для преобразования чисел в OFMT, см. далее). По умолчанию - %.6g.
ENVIRON
Массив, представляющий окружение. Индексами служат
FILENAME
Имя файла, из которого в данный момент производится ввод.
FNR
Порядковый номер текущей
FS
NF
Количество
NR
Порядковый номер текущей
OFMT
Формат вывода чисел, по умолчанию %.6g.
OFS
ORS
RLENGTH
Длина успешно match()
RS
Первым символом RS, является RS пусто, между записями может располагаться несколько пустых строк.
RSTART
Начальная позиция успешно match()
SUBSEP
Приведем примеры использования утилиты . Сложить числа, стоящие в первом
{ s += $1 } END { print "Сумма:", s,
" Среднее арифметическое:", s/NR }
Командная строка из
листинга 6.27, служит для вывода тех строк файла f1.txt, у
которых первое
awk '$1 != prev { print; prev = $1 }' f1.txt
Чтобы распечатать файл f2.txt, вставляя после prog. ) и командной строкой, представленными,
соответственно, в листингах
6.28 и 6.29.
/Page/ { $2 = n++ } { print }
awk -f prog.awk -v 'n=1' f2.txt
Программа, показанная в
листинге 6.30, выводит
{ for (i = NF; i > 0; --i) print $i }
Промоделировать работу утилиты echo можно с помощью
BEGIN {
for (i = 1; i < ARGC; ++i)
printf ("%s%s", ARGV [i],
i == ARGC - 1 ? "\n" : " ")
}
Следующая PATH,
по элементам массива.
BEGIN {
n = split (ENVIRON ["PATH"], path, ":")
for (i = 1; i <= n; ++i)
print path [i]
}
В листинге 6.33 приведен фрагмент командного файла, выполняемого при
выключении системы. Здесь можно обратить внимание на разные виды экранирования.
(Третье mount - это точка монтирования.)
# Перемонтируем на чтение все, что еще остается смонтированным.
mount | awk '/( \/ |^\/dev\/root)/ { print $3 }' | while read line; do
mount -n -o ro,remount $line
done
Отметим, что в POSIX-2001 стандартизована весьма развитая версия , входной
язык которой приближен к языку C.
На уровне функций работа с regex (см. листинг 6.34).
#include <regex.h>
int regcomp (regex_t *restrict preg,
const char *restrict pattern, int cflags);
int regexec (const regex_t *restrict preg,
const char *restrict string,
size_t nmatch, regmatch_t
pmatch [restrict], int eflags);
void regfree (regex_t *preg);
size_t regerror (int errcode, const regex_t
*restrict preg, char *restrict errbuf,
size_t errbuf_size);
Первый член этого семейства, функция regcomp(), pattern, и помещает результат компиляции в
структуру типа regex_t, на которую указывает аргумент preg. Эта структура,
описанная в заголовочном файле <regex.h>, должна содержать про крайней мере
size_t re_nsub; /* Число заключенных в скобки подвыражений */
Третий аргумент функции regcomp(), cflags, задается как побитное ИЛИ
следующих флагов:
REG_EXTENDED
Использовать
REG_ICASE
При
REG_NOSUB
В regexec() сообщать только об успехе/неудаче re_nsub структуры regex_t ).
REG_NEWLINE
Изменить трактовку переводов строк (мы не будем на этом останавливаться).
Функция regexec() сопоставляет string со скомпилированным шаблоном, заданным аргументом preg.
При успешном выполнении результат равен нулю; в противном случае возвращается ненулевое значение,
свидетельствующее о неудаче eflags - побитное
ИЛИ флагов REG_NOTBOL и REG_NOTEOL - определяет, являются ли границы ^ и $. Если
значение аргумента nmatch равно нулю или при вызове regcomp() был задан флаг REG_NOSUB, аргумент pmatch функции regexec() игнорируется.
В противном случае он должен указывать на массив не менее чем из nmatch элементов, который
будет заполнен смещениями pmatch [0] соответствует всему
Структурный тип regmatch_t должен включать по крайней мере следующие
regoff_t rm_so; /* Смещение в байтах начала подцепочки от начала цепочки */ regoff_t rm_eo; /* Смещение в байтах первого символа за концом подцепочки от начала цепочки */
Тип regoff_t определяется как целое со знаком, способное вместить любое
значение типов off_t и ssize_t.
Функция regfree() освобождает память, запрошенную вызовом regcomp() с тем же
значением аргумента preg, которое после этого нельзя использовать как
указатель на
В файле <regex.h> определены константы, возвращаемые
функциями семейства regex() в случае ошибки. Например, значение REG_NOMATCH
возвращается функцией regexec() при неудаче REG_BADPAT
обозначает некорректное REG_ESPACE - нехватку
памяти и т.д. Функция regerror() отображает эти константы в
неспецифицируемые стандартом errbuf.
Приложение, вызывая regerror(), должно передать в качестве аргумента errcode
последнее ненулевое значение, возвращенное функциями regcomp() или regexec()
с заданным значением аргумента preg.
Приведем пример использования функций семейства regex() (см.
листинг 6.35).
Обратим внимание на задание флага REG_NOTBOL при повторных обращениях к regexec().
#include <stdio.h>
#include <limits.h>
#include <regex.h>
/* Программа ищет все вхождения заданного шаблона во всех входных строках */
/* и выводит успешно сопоставленные подцепочки */
#define PATTERN "[A-Za-z][A-Za-z0-9]{0,31}"
int main (void) {
char line [LINE_MAX]; /* Буфер для входных строк */
char *pline; /* Указатель на начало сопоставляемой части строки */
regex_t cere; /* Скомпилированное расширенное регулярное выражение */
regmatch_t pm; /* Структура для запоминания границ сопоставленной подцепочки */
int reerrcode; /* Код ошибки от regcomp или regexec */
char reerrbuf [LINE_MAX]; /* Буфер для строк с сообщениями об ошибках */
int i;
if ((reerrcode = regcomp (cere, PATTERN, REG_EXTENDED)) != 0) {
(void) regerror (reerrcode, cere, reerrbuf, sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (cere);
return (reerrcode);
}
fputs ("Вводите строки, сопоставляемые с шаблоном " PATTERN "\n", stdout);
while (fgets (line, sizeof (line), stdin) != NULL) {
/* Произведем первое сопоставление с прочитанной строкой. */
/* Оно отличается от остальных при наличии в шаблоне фиксатора начала */
reerrcode = regexec (cere, pline = line, 1, pm, 0);
while (reerrcode == 0) {
/* Повторяем, пока сопоставления с остатком строки успешны */
fputs ("Сопоставленная подцепочка: ", stdout);
for (pline += pm.rm_so, i = pm.rm_eo - pm.rm_so; i-- > 0; ) {
fputc (*pline++, stdout);
}
fputc ('\n', stdout);
reerrcode = regexec (cere, pline, 1, pm, REG_NOTBOL);
}
}
regfree (cere);
return (ferror (stdin) || ferror (stdout));
}
Читателю рекомендуется поэкспериментировать с шаблоном PATTERN, пробуя
различные варианты, в том числе некорректные.
Идейно простым, но весьма мощным и полезным средством обработки текстовых
файлов является служебная программа преобразования символов tr:
tr [-c | -C] [-s] цепочка1 цепочка2 tr -s [-c | -C] цепочка1 tr -d [-c | -C] цепочка1 tr -ds [-c | -C] цепочка1 цепочка2
Она не применяет
Утилита tr копирует стандартный ввод на стандартный вывод с заменой либо
удалением выбранных символов. При отсутствии опций введенные символы,
найденные в цепочке1, заменяются на соответствующие (стоящие на тех же
относительных позициях) символы из цепочки2.
Опции -c и -C предписывают
использовать вместо цепочки1 ее дополнение до множества всех символов; в первом
случае дополнение упорядочивается в соответствии с кодировкой, во втором
- по алфавиту. По опции -d будут удалены все входные символы, заданные цепочкой1. Опция -s задает
Чтобы задавать в tr группы символов,
можно воспользоваться следующими конструкциями.
c1-c2
Обозначает c1 до c2 включительно.
[:класс_символов:]
Обозначает
[=класс_эквивалентности=]
Обозначает
[c*n]
Обозначает символ c, повторенный n раз.
Может использоваться только в цепочке2.
Если первая цифра в n есть 0, n рассматривается как восьмеричное число;
иначе - как десятичное. Нулевое или отсутствующее n воспринимается
как "очень много"; эта возможность полезна при дополнении цепочки2 до
длины цепочки1.
Обратный слэш можно использовать для задания управляющих символов
( '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v' ). Кроме того, \ обозначает код
символа, если за ним идут одна, две или три восьмеричные цифры.
Следующая команда (см.
листинг 6.36) помещает список всех f1,
по одному на строку, в файл f2 (под
tr -cs '[:alpha:]' '[\n*]' < f1 > f2
Команда, показанная в листинге 6.37, переводит большие буквы в малые, попутно сжимая последовательности одинаковых (без учета регистра) букв.
tr -s '[:upper:]' '[:lower:]'
Служебная программа uniq
uniq [-c | -d | -u] [-f число] [-s число]
[входной_файл [выходной_файл]]
позволяет сократить до одной подряд идущие одинаковые строки (сделать
одинаковые строки файла смежными можно с помощью утилиты sort ). Опции
предоставляют дополнительный сервис.
-c
Перед каждой выходной строкой помещать ее кратность во входном файле.
-d
Подавить вывод неповторяющихся строк.
-f число
При сравнении строк игнорировать заданное число начальных [[:blank:]]*[^[:blank:]]*
-s число
При сравнении строк игнорировать заданное число начальных символов. При
совместном использовании опций -f и -c игнорируется указанное число символов,
идущих после заданного числа
-u
Подавить вывод строк, повторявшихся во входном файле.
В качестве примера употребления утилиты uniq приведем конвейер,
позволяющий найти десять самых употребительных заголовочных файлов среди
включаемых в стандартные заголовочные файлы, расположенные в /usr/include и его
find /usr/include -name '*.h' -exec cat
{} \; | tr -d '[:blank:]' | \
grep -E -e '^#include(<.*>|".*")'
| sort | uniq -dc | sort -r | head
977 #include"nsISupports.h" 315 #include<glib.h> 201 #include<gdk/gdk.h> 167 #include<glibmm.h> 160 #include<features.h> 154 #include<glib-object.h> 144 #include"nsCOMPtr.h" 139 #include<sys/types.h> 139 #include<glibmm/class.h> 135 #include"nscore.h"
Служебная программа cut
cut -b список [-n] [файл ...]
cut -c список [файл ...]
cut -f список [-d разделитель]
[-s] [файл ...]
используется для выборки байт (опция -b ), символов ( -c ) либо
ограниченных разделителями -f ) с заданными списком номерами из строк исходных
файлов, их конкатенации и выдачи на стандартный вывод. Если применить
терминологию реляционных баз данных, cut выполняет
операцию
Список, являющийся -b, -c и -f, задается как
последовательность разделенных запятыми или пробелами положительных чисел или
диапазонов (с естественными умолчаниями, когда границы опущены). Опция -d
определяет разделитель -n предписывает не разрывать (многобайтные) символы, опция -s в
сочетании с -f подавляет вывод строк, в которых не оказалось символов-разделителей (по
умолчанию такие строки копируются на стандартный вывод без изменений).
Пример. Чтобы выделить из базы данных пользователей входные имена и идентификаторы, можно воспользоваться командой, показанной в листинге 6.40. Начальный фрагмент возможного результата приведен в листинге 6.41.
cut -d : -f 1,3 /etc/passwd
root:0 bin:1 daemon:2 adm:3 lp:4 sync:5 . . .
Служебная программа paste
paste [-s] [-d список] файл ...
в терминологии реляционных баз данных осуществляет -s конкатенируются строки
каждого из исходных файлов. Во всех случаях строки склеиваются посредством
символа табуляции (по умолчанию) или символов из списка - аргумента
опции -d. Список этих символов рассматривается как кольцевой, т. е. будучи
исчерпан, он используется повторно. Сочетание \0 в нем трактуется как пустая
В качестве имени исходного файла может быть задан минус, что означает стандартный ввод. Если минус употреблен многократно, то стандартный ввод читается построчно, циклически по именам - минусам. Любопытно отметить, что стандарт POSIX-2001 предписывает реализациям поддерживать обработку не менее двенадцати исходных файлов.
Рассмотрим несколько примеров. Для выдачи в четыре
ls | paste - - - -
Для попарного
paste -s -d "\0\n" f.txt
Если файл не подпадает под определение текстового из-за чрезмерно длинных
строк, утилитой cut можно выделить начальные байты, поместив "хвосты" строк
в другой файл. В дальнейшем из двух полученных файлов с помощью
служебной программы paste можно воссоздать исходный (см.
листинг 6.44).
cut -b 1-80 -n f > f1.txt cut -b 81- -n f > f2 . . . paste -d '\0' f1.txt f2 > f3
Еще один join - выдает на стандартный
вывод результат файла1 и файла2:
join [-a номер_файла | -v номер_файла] [-e цепочка] [-o список] [-t символ] [-1 номер_поля] [-2 номер_поля] файл1 файл2
Отношения файл1 и файл2 должны быть
Результат операции составляют строки, по одной для каждой пары из отношений файл1 и файл2, имеющих одинаковые файл1, затем
остатка строки отношения файл2.
Как правило,
Допустимы следующие опции.
-a номер_файла
В дополнение к обычному выводу выдать строку для каждой непарной строки из файла с указанным номером (1 или 2).
-e цепочка
Заменить пустые -o
заданной
-o список
Составлять выходные строки из номер_файла.номер_поля или
-t символ
Использовать символ в качестве разделителя. Каждое вхождение символа в строку значимо. Указанный символ используется как разделитель и при вводе, и при выводе.
-v номер_файла
Вместо подразумеваемого вывода выдавать только непарные строки из файла с указанным номером (1 или 2).
-1 номер_поля
Производить соединение по файла1 с
заданным номером.
-2 номер_поля
Производить соединение по файла2 с заданным номером.
Рассмотрим примеры. Командная строка (см.
листинг 6.45) выполняет соединение
баз данных пользователей и групп,
join -1 4 -2 3 -o 1.1,2.1,1.6 -t :
passwd.sorted group.sorted
halt:root:/sbin operator:root:/root root:root:/root shutdown:root:/sbin sync:root:/sbin bin:bin:/bin daemon:daemon:/sbin . . .
Пусть имеется два упорядоченных по алфавиту справочника: номера телефонов
и адреса электронной почты (см.
листинг 6.47). Предполагается, что в
качестве разделителя
Имя Номер телефона Иван 123-4567 Петр 123-5678 Яков 123-6789 Имя Адрес электронной почты Иван ivan123@mail.ru Олег oleg@yahoo.com Яков yak@yandex.ru
join -t '<tab>' -a 1 -a 2 -e '---------'
-o 0,1.2,2.2 phone.txt email.txt
Имя Номер телефона Адрес электронной почты Иван 123-45-67 ivan123@mail.ru Олег --------- oleg@yahoo.com Петр 123-56-78 --------- Яков 123-67-89 yak@yandex.ru
Читателю предлагается самостоятельно выбрать правильный способ задания
символа табуляции в качестве -t служебной программы join, а также объяснить, зачем нужен пробел в начале
Обработка opendir()
(см. листинг 6.50).
#include <dirent.h> DIR *opendir (const char *dirname);
После открытия текущим становится первый rewinddir() (см. листинг 6.51).
#include <dirent.h> void rewinddir (DIR *dirp);
Чтение readdir()
(см. листинг 6.52),
которая возвращает указатель на структуру, представляющую текущий errno перед
вызовом readdir(), а затем, если
результат равен NULL, проанализировать это значение.
#include <dirent.h> struct dirent *readdir (DIR *dirp);
Согласно стандарту POSIX-2001, структура dirent содержит по крайней мере одно
char d_name []; /* Имя файла */
В качестве необязательного описано еще одно
ino_t d_ino; /* Порядковый номер файла */
Если
Следует учитывать, что указатель, возвращаемый функцией readdir(), может
ссылаться на область памяти, перезаписываемую другими обращениями к readdir()
с тем же значением аргумента dirp. Кроме того, нужно помнить и о том, что
содержимое читаемого
После завершения работы с closedir() (см. листинг 6.53),
возвращающей
#include <dirent.h> int closedir (DIR *dirp);
Нередко fnmatch() (см. листинг 6.54).
#include <fnmatch.h> int fnmatch (const char *file_pattern, const char *file_name, int flags);
На процесс file_name
с file_pattern влияют следующие флаги:
FNM_PATHNAME
Трактовать имя file_name как маршрутное. Символу / в имени должен
явным образом сопоставляться этот же символ в шаблоне (а не ?
или / трактуется наравне с другими.
FNM_NOESCAPE
При наличии этого флага символ \ трактуется наравне с другими. В противном
случае он играет экранирующую роль.
FNM_PERIOD
Если этот флаг установлен, точка в начале имени файла должна сопоставляться с точкой в шаблоне. Иначе точка в начале имени сопоставляется на общих основаниях.
В случае успешного fnmatch() возвращает ноль,
при неудаче результат равен FNM_NOMATCH, в случае ошибки возвращается
другое ненулевое значение.
В качестве примера употребления описанных функций рассмотрим
программу, которая выводит имена файлов текущего
#include <dirent.h>
#include <fnmatch.h>
#include <errno.h>
#include <stdio.h>
/* Программа сопоставляет имена файлов текущего каталога с заданными шаблонами */
#define SEARCH_DIR "."
static void match_names (DIR *dirp, const char *pattern) {
struct dirent *dp;
rewinddir (dirp);
while (errno = 0, (dp = readdir (dirp)) != NULL) {
if (fnmatch (pattern, dp->d_name, FNM_PERIOD) == 0) {
(void) printf (" %s\n", dp->d_name);
}
}
if (errno != 0) {
perror ("Ошибка при чтении каталога " SEARCH_DIR);
}
}
int main (int argc, char *argv []) {
DIR *dirp;
int i;
if ((dirp = opendir (SEARCH_DIR)) == NULL) {
perror ("Ошибка при открытии каталога " SEARCH_DIR);
return (-1);
}
for (i = 1; i < argc; i++) {
(void) printf ("Файлы каталога " SEARCH_DIR ", удовлетворяющие шаблону %s\n", argv [i]);
match_names (dirp, argv [i]);
}
return (closedir (dirp));
}
Справедливости ради нужно отметить, что приведенный пример носит искусственный
характер, поскольку для glob()
(см. листинг 6.56).
#include <glob.h> int glob (const char *restrict file_pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *restrict pglob); void globfree (glob_t *pglob);
Функция glob() сопоставляет все доступные маршрутные имена с file_pattern и генерирует список успешно glob() возвращает в структуре типа glob_t, содержащей,
согласно стандарту, по крайней мере следующие
size_t gl_pathc; /* Число успешно сопоставленных маршрутных имен */ char **gl_pathv; /* Массив указателей на успешно сопоставленные маршрутные имена */ size_t gl_offs; /* Число элементов, которые нужно зарезерви- ровать в начале массива gl_pathv */
Структура, на которую указывает аргумент pglob, должна создаваться
приложением. Другие области памяти, в том числе массив gl_pathv, резервируются
функцией glob() по мере необходимости и освобождаются после обращения к globfree() с тем же значением pglob.
Работой функции glob() можно управлять с помощью следующих флагов.
GLOB_APPEND
Добавлять вновь glob().
GLOB_DOOFFS
Принимать во внимание gl_offs.
Если этот флаг установлен, то pglob->gl_pathv будет указывать
на pglob->gl_offs пустых указателей, за которыми
следуют pglob->gl_pathc указателей на маршрутные имена и завершающий пустой
указатель.
GLOB_ERR
Завершать работу по достижении glob() продолжает процесс
GLOB_MARK
Добавлять символ / после имен успешно
GLOB_NOCHECK
При отсутствии успешно
GLOB_NOESCAPE
Запретить экранирование символом \.
GLOB_NOSORT
Не
Если в процессе своей работы функция glob() достигает errfunc отличен от пустого
указателя, то glob() вызывает (*errfunc ()) с двумя аргументами:
"проблемным" маршрутным именем и соответствующим значением errno.
Если этот вызов возвращает значение, отличное от нуля, или если установлен флаг GLOB_ERR, pglob->gl_pathc и pglob->gl_pathv устанавливаются в соответствии с уже обработанными маршрутами, а
результат вызова функции glob() полагается равным GLOB_ABORTED (при
нормальном завершении возвращается 0).
Перепишем программу, которая выводит имена файлов, удовлетворяющие заданным в
командной строке шаблонам, воспользовавшись функцией glob()
(см. листинг 6.57).
#include <glob.h>
#include <errno.h>
#include <stdio.h>
/* Программа выводит маршрутные имена, сгенерированные по заданным шаблонам */
static int errfunc (const char *epath, int eerrno) {
fprintf (stderr, "Ошибка при обработке каталога %s: ", epath);
errno = eerrno;
perror (NULL);
return (0);
}
int main (int argc, char *argv []) {
glob_t gl_buf;
int i;
for (i = 1; i < argc; i++) {
(void) glob (argv [i], ((i == 1) ?
}
(void) printf ("Маршрутные имена, сгенерированные по заданным шаблонам:\n");
for (i = 0; (unsigned) i < gl_buf.gl_pathc; i++) {
(void) printf ("%s\n", gl_buf.gl_pathv [i]);
}
globfree (gl_buf);
return (0);
}
Выше, при описании языка shell, мы рассматривали служебную программу . Ее логическим дополнением является утилита dirname:
dirname цепочка_символов
Она выдает на стандартный вывод имя dirname как
В качестве примера использования утилиты dirname приведем фрагмент
командного файла, выполняемого при загрузке ОС Linux
(см. листинг 6.58).
if [ "`dirname $RAW`" = "/dev/raw" -a -f /dev/raw ]; then echo $" Please correct your /etc/sysconfig/rawdevices:" echo $" rawdevices are now located in the directory /dev/raw/ " echo $" If the command 'raw' still refers to /dev/raw as a file." echo $" you'll have to upgrade your util-linux package" exit fi
Совместное использование утилит и dirname иллюстрирует
листинг 6.59.
Это командный файл с одним аргументом - маршрутным именем
компилируемого C-файла, которое может быть задано как с расширением .c,
так и без него.
gcc -Wall -W -pedantic -o $(basename "$1" .c)
$(dirname "$1")/$(basename "$1" .c).c
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.