Руководство пользователя для GNU Awk

Arnold D. Robbins
перевод Балуева А. Н.

5. Чтение входных файлов

Оглавление
В начало страницы

В обычной awk-программе весь вход читается либо со стандартного входа (по умолчанию с клавиатуры, но часто и с конвейера из другой команды ) или с файлов, имена которых вы указываете в командной строке awk.Если вы указываете входные файлы, awk читает их подряд, сначала все данные с одного, затем переходит к следующему. Имя текущего входного файла хранится в встроенной переменной FILENAME (см. Главу 10 [Встроенные переменные], стр. 115).

Ввод читается в единицах, называемых записями, и обрабатывается по правилам вашей программы запись за записью. По умолчанию, каждая запись есть одна строка (line). Каждая запись автоматически разделяется на части, называемые полями. Это делает более удобным для программы обработку частей записи. В редких случаях вам нужно использовать команду getline. Она нужна тогда, когда нужен ввод с файлов не подряд, и она позволяет не указывать имена файлов в команде awk (см. раздел 5.8 [Явный ввод с помощью getline], стр. 53).

5.1 Как вход делится на записи

В начало страницы

Интерпретатор awk разделяет ввод для вашей программы на записи и поля. Записи разделяются знаками, называемыми разделителями записей. По умолчанию, это знаки newline. Поэтому по умолчанию записи совпадают со строками. Вы можете использовать другие символы как разделители записей, присваивая их встроенной переменной RS.

Значение RS можно менять в awk-программе, подобно другим переменным, оператором присваивания `=' (см. раздел 7.7 [Присваивающие выражения], стр. 84). Новый разделитель записей нужно заключать в кавычки для строковой константы. Обычно это делается в начале исполнения, до обращения к вводу, так что самая первая запись будет читаться с нужным разделителем. Чтобы сделать это, используйте специальный образец в BEGIN (см. раздел 8.1.5 [Специальные образцы BEGIN и END], стр. 100).

 Например:

awk 'BEGIN - RS = "/" "" ; - print $0 ""' BBS-list

изменяет значение RS на "/" до чтения ввода. Это цепочка, первый символ в которой есть слеш; в результате записи разделяются слешами. Затем читается входной файл и второе правило в awk-программе (действие без образца) печатает каждую запись. Поскольку каждый оператор печати добавляет newline в конец вывода, в результате выполнения этой awk-программы будет получена копия ввода, где каждый слеш заменен на newline.

Вот результат исполнения программы на  `BBS-list':

$ awk 'BEGIN - RS = "/" "" ; - print $0 ""' BBS-list
a aardvark 555-5553 1200 
a 300 B 
a alpo-net 555-3412 2400 
a 1200 
a 300 A
a barfly 555-7685 1200 
a 300 A 
a bites 555-1675 2400 
a 1200 
a 300 A
a camelot 555-0542 300 C 
a core 555-2912 1200 
a 300 C 
a fooey 555-1234 2400
a 1200 
a 300 B 
a foot 555-6699 1200 
a 300 B 
a macfoo 555-6480 1200 
a 300 A
a sdace 555-3430 2400 
a 1200 
a 300 A 
a sabafoo 555-2127 1200 
a 300 C
a

Заметим, что запись с `camelot' BBS не разделена. В оригинальном файле данных (см. раздел 1.3 [Файлы с данными для примеров], стр. 7), эта строка выглядит так:

camelot 555-0542 300 C

Она содержит только одну baud rate; поэтому в записи нет слешей. Другой способ изменить разделитель записей есть командная строка, использующая свойство присваивания переменной (см. раздел 14.2 [Другие аргументы командной строки], стр. 165).

awk '- print $0 ""' RS="/" BBS-list

Это присваивает RS значение `/' перед обработкой `BBS-list'. Употребление необычного символа, такого как `/', для разделения записей приводит к правильному поведению в подавляющем большинстве случаев. Однако, следующий (экстремальный) конвейер печатает неожиданную `1'. Имеется одно поле, состоящее из newline. Значение встроенной переменной NF есть количество полей в текущей записи.


$ echo -- awk 'BEGIN - RS = "a" "" ; - print NF ""'

a 1

Достижение конца ввода заканчивает текущую входную запись, даже если последний символ в файле не есть символ из RS (d.c.).

Пустая цепочка "" (цепочка без символов) имеет специальный смысл в качестве значения RS: она означает, что записи разделяются одним или больше пробелами, и ничем другим. См. раздел 5.7 [Многострочные записи], стр. 51, для деталей.

Если изменить значение RS в процессе исполнения awk, новое значение будет использоваться для разделения следующих записей после окончания обработки текущей записи с прежним разделителем. По достижении конца этой записи gawk устанавливает переменную RT по тексту во вводе, предназначенному для RS. Значения RS не ограничиваются одно-символьными цепочками. Это может быть любое регулярное выражение (см. Главу 4 [Регулярные выражения], стр. 23). В общем случае, запись оканчивается на первой цепочке, соответствующей этому регулярному выражению; следующая запись начинается после конца этой цепочки. Это общее правило работает и в обычном случае, когда RS имеет значение newline: запись кончается по началу следующей обнаруженной строки (следующее newline в вводе) и следующая запись начинается сразу после конца этой строки (с первого символа следующей). Символ newline, поскольку он соответствует RS, не является частью записи.

Когда RS есть простой символ, RT будет содержать то же значение. Однако, если RS есть регулярное выражение, RT становится более полезной; она содержит фактически входной текст, который соответствует этому регулярному выражению. Следующий пример иллюстрирует обе эти особенности. Он устанавливает RS равной регулярному выражению, которое соответствует или newline, или ряду из одной или более букв верхнего регистра, выборочно начинающейся и/или кончающейся белым пробелом (см. Главу 4 [Регулярные выражения], стр. 23).


$ echo record 1 AAAA 
record 2 BBBB 
record 3 -- ? 
gawk 'BEGIN - RS =
""n--( *[[:upper:]]+ *)" 
"" ? - print "Record =", $0, "and RT =", RT ""'

a Record = record 1 and RT = AAAA 
a Record = record 2 and RT = BBBB
a Record = record 3 and RT = 
a

Конечная строка выхода имеет дополнительную строку пробелов. Это происходит потому, что значение RT есть newline, и тогда оператор print выдает свою собственную заключительную newline. См. раздел 16.2.8 [Простой поточный редактор], стр. 242, о более интересном примере с RS как regexp и с RT.

Использование RS в качестве регулярного выражения и переменной RT есть расширения gawk; они отсутствуют в режиме эмуляции (см. раздел 14.1 [параметры командной строки], стр. 161). В режиме эмуляции только первый символ в значении RS используется для определения конца записи. Интерпретатор awk запоминает количество записей, прочитанных им из текущего входного файла. Это число хранится в переменной FNR. Она сбрасывается на 0 в начале чтения каждого файла. Другая встроенная переменная, NR, содержит полное количество записей, прочтенных из входных файлов с данными. Она начинает с 0 и никогда не сбрасывается автоматически на 0.

5.2 Обследование полей

В начало страницы

Когда awk читает входную запись, она автоматически разделяется интерпретатором на части, называемые полями. По умолчанию, поля разделяются пробелами, как слова в строке. Пробел в строке awk означает один или более пробелов, знаков tabs или newlines; другие символы, такие как formfeed и пр., которые имеют смысл пробелов (whitespace) в других языках, в awk не считаются таковыми. Назначение полей --- облегчить доступ к соответствующим частям записи. Если вы не хотите этим пользоваться, вы можете оперировать с целой записью, но поля --- это то, что делает простые программы awk очень удобными. Для ссылки на поле в awk-пррограмме используют знак доллара,

 `$', с номером нужного поля после него. 
 Так, $1 есть ссылка на первое поле,
 
 $2 --- на второе и т.д. 

 Предположим, строка ввода есть:
 
 This seems like a pretty nice example.

Здесь первое поле, или $1, есть `This'; 
второе поле, или $2, есть `seems'; и т.д. 
Заметим, что последнее поле, $7, есть  `example.'. 
Так как нет пробела
между `e' и `.', точка входит состав седьмого поля.

Значение встроенной переменной NF есть количество полей в текущей записи. awk обновляет значение NF автоматически при каждом чтении записи. Независимо от количества полей, последнее поле записи может быть представлено как $NF. Таким образом, в предыдущем примере $NF будет то же, что и $7, т.е. `example.'. Как это работает, объясняется ниже (см. раздел 5.3 [Непостоянные номера полей], стр. 41). Если вы пытаетесь сослаться на поле после последнего, $8, когда запись имеет только 7 полей, вы получаете пустую цепочку.

В POSIX awk символы newline не рассматриваются как пробелы (whitespace) для разделения полей. $0, что выглядит как ссылка на " нулевое" поле, представляет специальный случай: она представляет всю входную запись. $0 используется, когда вы не заинтересованы в поляхs.

Приведем несколько примеров.

$ awk '$1 ~ /foo/ - print $0 ""' BBS-list

a fooey 555-1234 2400/1200/300 B 
a foot 555-6699 1200/300 B
a macfoo 555-6480 1200/300 A 
a sabafoo 555-2127 1200/300 C

Этот пример печатает каждую запись из файла `BBS-list', у которой первое поле содержит цепочку `foo'. Оператор `~' называется оператор соответствия (см. раздел 4.1 [Как использовать регулярные выражения], стр. 23); он проверяет соответствие цепочки (здесь это поле $1) данному регулярному выражению. Следующий пример ищет `foo' в целой записи и печатает первое и последнее поля каждой входной записи, удовлетворяющей такому соответствию:

$ awk '/foo/ - print $1, $NF ""' BBS-list
a fooey B 
a foot B 
a macfoo A 
a sabafoo C

5.3 Непостоянные номера полей

В начало страницы

Номер поля не обязан быть константой. Любое выражение языка awk может быть использовано после `$' для ссылки на поле. Значение выражения указывает номер поля. Если значение есть не число, а цепочка, она конвертируется в номер.

Рассмотрим такой пример:

awk '- print $NR ""'

Напомним, что NR есть количество прочитанных до настоящего момента записей: один для первой записи, два во второй, и т.д. Так что этот пример печатает первое поле первой записи, второе поле второй записи, и т.д. Для двадцатой записи печатается поле номер 20; обычно запись имеет меньше 20 полей, так что это будет пустая строка.

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

awk '- print $(2*2) ""' BBS-list

awk должен вычислить выражение `(2*2)' и использовать его значение как номер поля для печати. Знак `*' означает умножение, так что выражение `2*2' вычисляется как четыре. Скобки употреблены для того, чтобы умножение было произведено до операции `$'; они необходимы всегда, когда в выражении для номера поля встречается бинарная операция. Наш пример поэтому печатает операционные часы (четвертое поле) каждой строки файла `BBS-list'.

(Все операторы awk перечислены в порядке убывания приоритета в разделе 7.14 [Приоритет операторов (Как операторы гнездятся)], стр. 94.) Если вычисленный номер поля есть 0, вы получаете всю запись. Так, $(2-2) имеет тот же смысл, что и $0. Отрицательные номера полей недопустимы; такая ссылка обычно приводит к прекращению исполнения программы. (Стандарт POSIX не предусматривает отрицательной ссылки на номер записи. gawk замечает это и прекращает выполнение программы. Другие реализации awk могут вести себя по-другому.)

Как упоминалось в разделе 5.2 [Обследование полей], стр. 40, количество полей текущей записи содержится в встроенной переменной NF (см. также Гл. 10 [Встроенные переменны, стр. 115). Выражение $NF не имеет специального смысла и использует значение NF как номер поля.

5.4 Изменение содержимого поля

В начало страницы

Вы можете изменять содержимое поля, прочтенное awk, внутри awk-программы; Эти изменения затрагивают только информацию, воспринятую программой как текущая входная запись. (Сам ввод остается неизменным, awk никогда не изменяет входной файл.)

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

$ awk '- $3 = $2 - 10; 
print $2, $3 ""' inventory-shipped

a 13 3 
a 15 5 
a 15 5...

Знак `-' означает вычитание, так что эта программа изменяет поле три, $3, присваивая ему значение поля 2 минус десять, `$2 - 10'. (См. раздел 7.5 [Арифметические операции], стр. 82.) Затем поле два и новое значение для поля три печатаются.

Для того, чтобы все это работало, текст в поле $2 должен иметь смысл как число; цепочка символов должна быть превращена в число, над которым компьютер может произвести арифметические действия. Результат вычитания конвертируется опять в цепочку символов, которая становится полем три. См. раздел 7.4 [Конверсия цепочек и чисел], стр. 81.

Когда вы изменяете значение поля (воспринятого программой awk), текст входной записи пере вычисляется, чтобы содержать новое поле там, где было старое. Поэтому $0 изменяется соответственно измененным полям. Таким образом, программа печатает копию входного файла, в которой вторые поля в каждой записи уменьшены на 10.


$ awk '- $2 = $2 - 10; 
print $0 ""' inventory-shipped

a Jan 3 25 15 115 
a Feb 5 32 24 226 
a Mar 5 24 34 228...

Вы можете также присваивать содержание полям, 
выходящим за рамки записи.

Например,

$ awk '- $6 = ($5 + $4 + $3 + $2) ? 
print $6 ""' inventory-shipped

a 168 
a 297 
a 301 ...

Мы создали $6, Значение которого есть сумма полей $2, $3, $4 и $5. Знак `+' представляет сложение. Для файла `inventory-shipped' $6 представляет общее количество пакетов, посланных морем в определенный месяц.

Создание нового поля изменяет внутреннюю копию текущей записи, сделанную awk-программой, т.е. значение $0. Так, если вы выполняете `print $0' после добавления поля, печатается запись с добавленным полем и с соответствующим количеством разделителей полей между ним и существовавшими ранее полями.

Такое пере вычисление зависит от NF и изменяет NF (количество полей; см. раздел 5.2 [Обследование полей], стр.40), и вследствие свойства, которое еще не рассматривалось, изменяет также разделитель выходных полей, OFS, который используется для разделения полей (см. раздел 6.3 [Выходные разделители], стр. 63). Например, NF присваивается значение номера старшего поля, которое вы создали.

Заметим вместе с тем, что одна только ссылка на поле вне рамок записи не изменяет значения ни $0 ни NF. Ссылка на поле вне записи производит только пустую цепочку.

Например,

if ($(NF+1) != "") 
	print "can't happen" 
		else print "everything is normal"

напечатает `everything is normal', потому что NF+1 конечно выходит за рамки. (См. раздел 9.1 [Оператор if-else], стр. 105, описывающий подробно операторы if-else. См. раздел 7.10 [Печать переменных и выражения сравнения], стр. 88, с подробной информацией об операторе `!='.)

Важно заметить, что присваивание значения существующему полю изменяет значение $0, но не меняет значение NF, даже если вы присваиваете пустую цепочку полю.

Например:

$ echo a b c d -- awk '- OFS = ":"; 
$2 = "" ? print 
$0; print NF ""'
a a::c:d
a 4

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

$ echo a b c d -- awk '- OFS = ":"; 
$2 = ""; 
$6 = "new" ? 
print $0;
print NF ""'
a a::c:d::new
a 6

Создается вставленное поле $5 с пустым значением (оно показано второй парой соседних двоеточий, а NF получает значение шесть. Уменьшение NF привет к потере значений полей, номера которых больше значения NF, и к пере вычислению $0. Вот соответствующий пример:


$ echo a b c d e f -- ../gawk '- print "NF =", NF;
? NF = 3; print $0 ""'
a NF = 6
a a b c

5.5 Задание разделителей полей

В начало страницы

Этот раздел довольно длинен; в нем описывается одна из наиболее фундаментальных операций в awk.

5.5.1 Основные сведения о разделении полей

В начало страницы

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

В дальнейших примерах мы используем маркирующий символ "ffl" для представления пробелов в выходе. Если разделитель полей есть `oo', то следующая строка:

moo goo gai pan

разбивается на три поля: `m', `fflg' и `fflgaifflpan'. Отметим ведущие пробелы в значениях второго и третьего полей. Разделитель полей представляется встроенной переменной FS. Системные программисты, обратите внимание! В awk не используется имя IFS, используемое оболочками, совместимыми с POSIX (такими как Bourne shell, sh, или GNU BourneAgain Shell, Bash).

В awk-программе можно менять значение FS оператором присваивания, `=' (см. раздел 7.7 [Присваивающие выражения], стр. 84). Часто это удобно делать в начале выполнения, перед началом обработки ввода, так что самая первая запись будет читаться с правильным разделителем. Чтобы это сделать, используйте специальный образец BEGIN (см. раздел 8.1.5 [Специальные образцы BEGIN и END], стр. 100).

Например, здесь мы присваиваем FS значение цепочки ",":

awk 'BEGIN - FS = "," "" ; - print $2 ""'

Из входной строки

John Q. Smith, 29 Oak St., Walamazoo, MI 42139

эта awk-программа извлечет и  напечатает цепочку 

 `ffl29fflOakfflSt.'.

Иногда входные данные содержат разделительные символы, которые не разделяют поля таким образом, как вы полагаете, что они должны разделять. Например, личное имя в предыдущем примере может иметь добавкой титул или суффикс, такой как `John Q. Smith, LXIX'. Для входной записи с таким именем: John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139 предыдущая программа извлечет `fflLXIX' вместо `ffl29fflOakfflSt.'. Если вы ожидаете, что программа напечатает адрес, вы будете очень удивлены. Мораль такова: выбирайте структуру данных и символы-разделители тщательно, чтобы предотвратить подобные случаи.

Как вы знаете, по умолчанию поля разделяются последовательностями белых пробелов (т.е. (пробелами, знаками tab и newline), но не единичными пробелами: два пробела подряд не ограничивают пустое поле. По умолчанию разделитель полей FS имеет значение цепочки, содержащей один пробел " ". Если бы это значение интерпретировалось обычным путем, т.е. каждый пробел считался разделителем полей, то два пробела подряд содержали бы между собой пустое поле. Этого не происходит, потому что единственный пробел в качестве значения FS представляет специальный случай: он означает разделение полей по умолчанию. Если FS имеет значением какой-нибудь другой отдельный символ, такой как ",", то каждое вхождение этого символа разделяет два поля. Два последовательных вхождения ограничивают пустое поле. Если символ стоит в начале или конце строки, то тоже отделяет пустое поле. Символ пробела есть единственный одиночный символ, который не подчиняется этим правилам.

5.5.2 Использование регулярных выражений для разделения полей

В начало страницы

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

Например, присваивание:

FS = ", "t"

делает каждую часть входной строки, состоящую из запятой с последующим пробелом и tab, разделителем полей. (`"t' есть управляющая последовательность, которая обозначает знак tab, см. раздел 4.2 [Управляющие последовательности], стр. 24, содержащий полный список управляющих последовательностей.)

А вот менее тривиальный пример регулярного выражения. Предположим, вам нужно иметь разделителями отдельные пробелы, как выше для этого использовались отдельные запятые. Вы можете присвоить FS "[ ]" (левая квадратная скобка, пробел, правая квадратная скобка). Это регулярное выражение соответствует единственному пробелу и ничему другому (см. Главу 4 [Регулярные выражения], стр. 23).

Имеется важная разница между двумя случаями: `FS = " "' (одиночный пробел) и `FS = "[ "t"n]+"' (левая квадратная скобка, пробел, обратный слеш, "t", обратный слеш, "n", правая квадратная скобка, составляющие регулярное, выражение, соответствующее одному или более пробелам, tab или newline). Для обоих FS поля разделяются группами пробелов, tab и/или newline. Однако, если значение FS есть " ", awk сначала убирает из записи ведущие и завершающие белые пробелы, а затем решает, как расположены записи.

Например, такой конвейер напечатает `b':

$ echo ' a b c d ' -- awk '- print $2 ""'
a b

Однако, следующий конвейер напечатает `a' (заметьте дополнительные пробелы вокруг каждой буквы):

$ echo ' a b c d ' -- awk 
	'BEGIN - FS = "[ "t]+" "" ? - print $2 ""'
a a

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

Например, рассмотрите такой конвейер:

$ echo ' a b c d' -- awk '- print; 
$2 = $2; 
print ""'
a a b c d
a a b c d

Первый оператор печати печатает запись как она прочиталась, с нетронутым ведущим белым пробелом. Присваивание $2 перестраивает $0 посредством конкатенации вместе от $1 до $NF, разделенных посредством значения OFS. Поскольку ведущие белые пробелы игнорируются при нахождении $1, они не служат частью нового $0. Окончательно, последний оператор печати печатает новую $0.

5.5.3 Превращение каждого символа в отдельное поле

В начало страницы

Бывают случаи, когда нужно рассматривать каждый символ записи отдельно. В gawk это сделать легко, нужно просто присвоить FS пустую цепочку (""). Тогда каждый отдельный символ в записи станет отдельным полем.

Вот пример:


$ echo a b -- gawk 
'BEGIN - FS = "" "" ? - ? 
for (i = 1; i != NF;
i = i + 1) ? print "Field", i, "is", $i ? ""'
a Field 1 is a
a Field 2 is
a Field 3 is b

Традиционно действия при FS равном "" были не определены. В таком случае Unix awk будет просто рассматривать всю запись как имеющую только одно поле (d.c.). В режиме эмуляции (см. раздел 14.1 [Параметры командной строки], стр. 161), если значением FS служит пустая цепочка, то gawk будет действовать так же.

5.5.4 Установка FS из командной строки

В начало страницы

FS может быть установлена из командной строки. Для этого нужно использовать параметр `-F'.

 Например,

awk -F, 'program' input-files

устанавливает в FS символ `,'. Заметьте, что параметром служит заглавное `F'. В отличие от этого `-f' указывает, что файл содержит программу awk. Регистр имеет значение в параметрах командной строки: параметры `-F' и `-f' не имеют ничего общего. Их можно использовать одновременно для установки переменной FS и получения awk-программы из файла.

Значение, используемое в качестве аргумента для `-F', обрабатывается точно так же как при присваивании встроенной переменной FS. Это значит, что если разделитель поля содержит специальные символы, они должны быть указаны соответствующими управляющими последовательностями.

Например, чтобы
использовать  `"' как разделитель полей, нужно напечатать:

# что-нибудь такое как FS = """" awk -F"""" '...' files ...

Поскольку `"' используется в оболочке как кавычка, awk увидит `-F""'. Тогда awk обработает `""' как управляющую последовательность (см. раздел 4.2 [Управляющие последовательности], стр. 24), и получит в результате одну `"' в качестве разделителя полей.

В специальном случае, в режиме эмуляции (см. раздел 14.1 [Параметры командной строки], стр. 161), если аргумент при `-F' есть `t', то FS получит значение символа tab. Это произойдет потому, что при печати `-F"t' в оболочке, без всяких кавычек, `"' удаляется, так что awk предположит, что на самом деле вы хотите разделять поля символами tab, а не `t'. Употребляйте `-v FS="t"' в командной строке, если вы на самом деле хотите отделять поля буквой `t' (см. раздел 14.1 [Параметры командной строки], стр. 161).

Например, воспользуемся программным файлом awk с именем `baud.awk', который содержит образец /300/ и действие `print $1'. Вот эта программа:

/300/ - print $1 ""

Установим также в FS символ `-' и исполним программу для входного файла `BBS-list'. Следующая команда напечатает список имен досок объявлений, которые работают со скоростью 300 бод, и первые три цифры их телефонных номеров:

$ awk -F- -f baud.awk BBS-list
a aardvark 555
a alpo
a barfly 555...

Обратите внимание на вторую строку вывода. В оригинальном входном файле (см. раздел 1.3 [Файлы с данными для примеров], стр. 7), вторая строка выглядит так:

alpo-net 555-3412 2400/1200/300 A

Символ `-', часть системного имени, использован как разделитель полей вместо `-' в телефонном номере, как было задумано. Это показывает, почему надо быть осторожным в выборе полей и разделителей записей. На многих системах Unix каждый пользователь имеет отдельный вход в системном файле с паролями, одну строку на пользователя. Информация в строке разделена на части двоеточиями. Первое поле содержит регистрационное имя пользователя, второе есть его секретный пароль.

Строка этого файла может выглядеть подобно следующей:

arnold:xyzzy:2076:10:Arnold Robbins:/home/arnold:/bin/sh

Следующая программа просматривает системный файл с паролями и печатает входы пользователей, не имеющих пароля:

awk -F: '$2 == ""' /etc/passwd

5.5.5 Обзор правил разделения на поля

В начало страницы

В соответствии со стандартом POSIX, awk должен вести себя так, как будто каждая запись разделяется на поля во время ее чтения. В частности, это означает, что можно менять значение FS после прочтения записи, и значения полей (т.е., как они были выделены) должны соответствовать старому значению FS, а не новому. Однако, многие реализации awk действуют не так. Вместо этого они откладывают выделение полей до ссылки на поле. Поля выделяются согласно текущему значению FS! (d.c.) Такое поведение может быть трудно диагнозируемым. Следующий пример иллюстрирует разницу между этими двумя методами. (Команда sed печатает первую строку из `/etc/passwd'. Утилита sed является "поточным редактором". Ее поведение также определяется стандартом POSIX.)

sed 1q /etc/passwd -- awk '- FS = ":" ; 

print $1 ""'


будет обычно печатать

root on an incorrect implementation of awk

в то время как  gawk напечатает что-нибудь вроде

root:nSijPlPhZZwgE:0:0:Root:/:

В следующей таблице указывается, как выделяются поля на основании значения переменной FS. (`==' означает "равно следующему.") FS == " " Поля разделяются белыми пробелами. Ведущие и завершающие белые пробелы игнорируются. Это же делается по умолчанию.

FS == любой другой отдельный символ. Поля разделяются каждым вхождением этого символа. Кратные последовательные вхождения ограничивают пустые поля, так же как ведущее и завершающее запись вхождения. Этот символ может также быть метасимволом регулярного выражения; его представление не нуждается в управляющей последовательности.

FS == регулярное выражение. Поля разделяются вхождениями символов, которые соответствуют регулярному выражению. Ведущее и завершающее вхождения отделяют пустые поля. FS == "" . Каждый отдельный символ в записи становится отдельным полем.

В начало страницы

<<< Оглавление Страницы: 5  6 >>>