Поиск по сайту:

Как использовать команду awk в Linux


В Linux awk — это динамо-машина для работы с текстом из командной строки, а также мощный язык сценариев. Вот введение в некоторые из его самых крутых функций.

Как awk получил свое название

Команда awk была названа с использованием инициалов трех человек, написавших исходную версию в 1977 году: Альфреда Ахо, Питера Вайнбергера и Брайана Кернигана. Эти трое принадлежали к легендарному пантеону UNIX компании AT&T Bell Laboratories. Благодаря вкладу многих других, с тех пор awk продолжает развиваться.

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

Правила, шаблоны и действия

awk работает с программами, которые содержат правила, состоящие из шаблонов и действий. Действие выполняется над текстом, соответствующим шаблону. Шаблоны заключаются в фигурные скобки ({}). Вместе шаблон и действие образуют правило. Вся программа awk заключена в одинарные кавычки ().

Давайте взглянем на самый простой тип программы awk. У него нет шаблона, поэтому он соответствует каждой строке введенного в него текста. Это означает, что действие выполняется в каждой строке. Мы будем использовать его в выводе команды who.

Вот стандартный вывод who:

who

Возможно, нам не нужна вся эта информация, мы просто хотим видеть имена в учетных записях. Мы можем направить вывод who в awk, а затем указать awk напечатать только первое поле.

По умолчанию awk считает поле строкой символов, окруженной пробелом, началом строки или концом строки. Поля обозначаются знаком доллара ($) и числом. Таким образом, $1 представляет собой первое поле, которое мы будем использовать с действием print для печати первого поля.

Набираем следующее:

who | awk '{print $1}'

awk печатает первое поле и отбрасывает остальную часть строки.

Мы можем напечатать столько полей, сколько захотим. Если мы добавим запятую в качестве разделителя, awk напечатает пробел между каждым полем.

Мы вводим следующее, чтобы также напечатать время, когда человек вошел в систему (четвертое поле):

who | awk '{print $1,$4}'

Есть пара специальных идентификаторов полей. Они представляют всю строку текста и последнее поле в строке текста:

  • $0: представляет всю строку текста.
  • $1: представляет первое поле.
  • $2: представляет второе поле.
  • $7: представляет седьмое поле.
  • $45: представляет 45-е поле.
  • $NF: обозначает количество полей и представляет последнее поле.

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

cat dennis_ritchie.txt

Мы хотим, чтобы awk печатал первое, второе и последнее поле цитаты. Обратите внимание, что несмотря на то, что он обёрнут в окне терминала, это всего лишь одна строка текста.

Набираем следующую команду:

awk '{print $1,$2,$NF}' dennis_ritchie.txt

Мы не знаем этой «простоты». является 18-м полем в строке текста, и нам все равно. Что мы знаем, так это то, что это последнее поле, и мы можем использовать $NF, чтобы получить его значение. Точка просто считается другим символом в теле поля.

Добавление разделителей полей вывода

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

date
date | awk '{print $2,$3,$6}'

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

date | awk 'OFS="/" {print$2,$3,$6}'
date | awk 'OFS="-" {print$2,$3,$6}'

Правила НАЧАЛА и КОНЦА

Правило BEGIN выполняется один раз перед началом любой обработки текста. Фактически, он выполняется еще до того, как awk прочтет какой-либо текст. Правило END выполняется после завершения всей обработки. У вас может быть несколько правил BEGIN и END, и они будут выполняться по порядку.

В нашем примере правила BEGIN мы напечатаем всю цитату из файла dennis_ritchie.txt, который мы использовали ранее, с заголовком над ней.

Для этого мы набираем эту команду:

awk 'BEGIN {print "Dennis Ritchie"} {print $0}' dennis_ritchie.txt

Обратите внимание, что правило BEGIN имеет собственный набор действий, заключенных в собственный набор фигурных скобок ({}).

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

who | awk 'BEGIN {print "Active Sessions"} {print $1,$4}'

Разделители полей ввода

Если вы хотите, чтобы awk работал с текстом, в котором не используются пробелы для разделения полей, вы должны сообщить ему, какой символ текст использует в качестве разделителя полей. Например, в файле /etc/passwd для разделения полей используется двоеточие (:).

Мы будем использовать этот файл и параметр -F (строка-разделитель), чтобы указать awk использовать двоеточие (:) в качестве разделителя. Мы вводим следующее, чтобы указать awk распечатать имя учетной записи пользователя и домашнюю папку:

awk -F: '{print $1,$6}' /etc/passwd

Выходные данные содержат имя учетной записи пользователя (или имя приложения или демона) и домашнюю папку (или расположение приложения).

Добавление узоров

Если все, что нас интересует, это учетные записи обычных пользователей, мы можем включить шаблон с нашим действием печати, чтобы отфильтровать все остальные записи. Поскольку число идентификаторов пользователей больше или равно 1000, мы можем основывать наш фильтр на этой информации.

Мы вводим следующее, чтобы выполнить наше действие печати только тогда, когда третье поле ($3) содержит значение 1000 или больше:

awk -F: '$3 >= 1000 {print $1,$6}' /etc/passwd

Шаблон должен непосредственно предшествовать действию, с которым он связан.

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

awk -F: 'BEGIN {print "User Accounts\n-------------"} $3 >= 1000 {print $1,$6}' /etc/passwd

Шаблоны — это полноценные регулярные выражения, и они — одно из достоинств awk.

Допустим, мы хотим увидеть универсальные уникальные идентификаторы (UUID) смонтированных файловых систем. Если мы ищем в файле /etc/fstab вхождения строки «UUID», он должен вернуть нам эту информацию.

Мы используем шаблон поиска «/UUID/» в нашей команде:

awk '/UUID/ {print $0}' /etc/fstab

Он находит все вхождения «UUID» и печатает эти строки. На самом деле мы получили бы тот же результат без действия print, потому что действие по умолчанию печатает всю строку текста. Однако для ясности часто полезно быть явным. Когда вы просматриваете сценарий или свой файл истории, вы будете рады, что оставили подсказки для себя.

Первая найденная строка была строкой комментария, и хотя строка «UUID» находится в середине, awk все же нашел ее. Мы можем настроить регулярное выражение и указать awk обрабатывать только строки, начинающиеся с «UUID». Для этого мы вводим следующее, которое включает токен начала строки (^):

awk '/^UUID/ {print $0}' /etc/fstab

Так-то лучше! Теперь мы видим только подлинные инструкции по монтированию. Чтобы еще больше уточнить вывод, мы вводим следующее и ограничиваем отображение первым полем:

awk '/^UUID/ {print $1}' /etc/fstab

Если бы на этой машине было смонтировано несколько файловых систем, мы бы получили аккуратную таблицу их UUID.

Встроенные функции

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

Чтобы продемонстрировать общую технику вызова функции, мы рассмотрим некоторые числовые. Например, следующий код выводит квадратный корень из 625:

awk 'BEGIN { print sqrt(625)}'

Эта команда печатает арктангенс 0 (ноль) и -1 (который оказывается математической константой пи):

awk 'BEGIN {print atan2(0, -1)}'

В следующей команде мы изменяем результат функции atan2() перед его печатью:

awk 'BEGIN {print atan2(0, -1)*100}'

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

awk 'BEGIN { print sqrt((2+3)*5)}'

awk-скрипты

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

В нашем примере скрипта мы собираемся сделать все следующее:

  • Сообщите оболочке, какой исполняемый файл использовать для запуска скрипта.
  • Подготовьте awk для использования переменной-разделителя полей FS для чтения входного текста с полями, разделенными двоеточиями (:).
  • Используйте разделитель выходных полей OFS, чтобы указать awk использовать двоеточие (:) для разделения полей в выходных данных.
  • Установите счетчик на 0 (ноль).
  • Установите во втором поле каждой строки текста пустое значение (это всегда x, поэтому нам не нужно его видеть).
  • Выведите строку с измененным вторым полем.
  • Увеличить счетчик.
  • Выведите значение счетчика.

Наш скрипт показан ниже.

Правило BEGIN выполняет подготовительные шаги, а правило END отображает значение счетчика. Среднее правило (у которого нет ни имени, ни шаблона, поэтому оно соответствует каждой строке) изменяет второе поле, печатает строку и увеличивает счетчик.

Первая строка скрипта сообщает оболочке, какой исполняемый файл использовать (в нашем примере awk) для запуска скрипта. Он также передает параметр -f (имя файла) в awk, который сообщает ему, что текст, который он будет обрабатывать, будет получен из файла. Мы передадим имя файла сценарию при его запуске.

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

#!/usr/bin/awk -f

BEGIN {
  # set the input and output field separators
  FS=":"
  OFS=":"
  # zero the accounts counter
  accounts=0
}
{
  # set field 2 to nothing
  $2=""
  # print the entire line
  print $0
  # count another account
  accounts++
}
END {
  # print the results
  print accounts " accounts.\n"
}

Сохраните это в файле с именем omit.awk. Чтобы сделать скрипт исполняемым, мы вводим следующее с помощью chmod:

chmod +x omit.awk

Теперь мы запустим его и передадим скрипту файл /etc/passwd. Это файл , который awk обработает для нас, используя правила внутри скрипта:

./omit.awk /etc/passwd

Файл обрабатывается, и каждая строка отображается, как показано ниже.

Записи «x» во втором поле были удалены, но обратите внимание, что разделители полей все еще присутствуют. Строки подсчитываются, и общее количество дается внизу вывода.

awk не означает неловкость

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

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

RELATED: Best Linux Laptops for Developers and Enthusiasts