Этот текст относится только к реализации GNU от awk , известной как ведьма gawk , является наиболее используемой и поставляется с любым современным распределением Linux / Unix .
[Руководство пользователя GNU AWK] [GNU-AWK] является его ссылкой, для примеров, которые я использовал в реальном мире, взяты в основном из моих ответов [STACKOVERFLOW] [SO].
Awk - это язык, похожий на Perl, лишь значительно более элегантный.
- Арнольд Роббинс
AWK - это язык программирования, разработанный для обработки текста и обычно используемый в качестве инструмента извлечения данных и отчетности. Это стандартная особенность большинства операционных систем Unix.
awk Award ...Его название происходит от фамилий его авторов - Альфреда Хо , Питера В. Энбергера и Брайана Кернигана .
awk ...Ищет строки, которые содержат определенные шаблоны в файлах или стандартный ввод.
В основном используется для извлечения данных и отчетности, например, обобщение информации из вывода других коммунальных программ.
C-like синтаксис.
Данные, управляемые: это описывает данные, с которыми вы хотите работать, а затем с каким действием, когда вы найдете их.
pattern { action }
pattern { action }Если программа короткая :
awk ' program ' input-file1 input-file2ПРИМЕЧАНИЕ. Остерегайтесь оболочки, цитируя проблемы 1 .
cmd | awk ' program ' ПРИМЕЧАНИЕ. pipe перенаправляет выходной команды левой руки ( cmd ) на вход команды awk 2 .
Когда код длинный , обычно удобнее положить его в файл и запустить его с такими командами:
awk -f program-file input-file1 input-file2
cmd | awk -f program-file Или просто сделайте его исполняемым, как shebang :
#! /bin/awk -f
BEGIN { print " hello world!! " } -F fs Установите переменную FS на fs .
-v var=val Установите переменную var на значение val перед началом выполнения программы.
Примечание : его можно использовать более одного раза, устанавливая другую переменную каждый раз.
Эти специальные шаблоны или блоки обеспечивают запуска и очистки для программ awk .
BEGIN{
// initialize variables
}
{
/pattern/ { action }
}
END{
// cleanup
}BEGIN до того, как первая входная запись будет считываться, END после того, как все ввод используется.
$ echo " hello " | awk ' BEGIN{print "BEGIN";f=1}
{print $f}
END{print "END"} '
BEGIN
hello
ENDgrepping awk ?? $ cat lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ grep dolor lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.$ awk ' /dolor/ ' lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.ПРИМЕЧАНИЕ. Если действие не дается действию по умолчанию , для печати записи, соответствующей данной шаблоне.
Но ... как мы можем узнать первое и последнее слово каждой строки?
Конечно, grep может, но нуждается в двух шагах:
$ grep -Eo ' ^[^ ]+ ' lorem_ipsum.dat
Lorem
Maecenas
Nunc
Curabitur
Lorem
Aliquam$ grep -Eo ' [^ ]+$ ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
ultrices. Давайте посмотрим на awk в действии здесь:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices. awk делит ввод для вашей программы на записи и поля .
Записи разделены символом, называемым сепаратором записей RS . По умолчанию сепаратор записи - это символ Unix Newline n .
Вот почему записи по умолчанию являются отдельными строками .
Кроме того, awk имеет сепаратор вывода ORS для управления тем, как записи представлены в stdout .
RS и ORS должны быть заключены в кавычки , которые указывают на константу строки.
Для использования другого символа или режима просто присвоить его переменным RS или / и ORS :
BEGIN , так что самая первая запись читается с помощью надлежащего разделителя.Примеры:
$ awk ' BEGIN{RS=" *, *";ORS="<<<---n"}
{print $0} ' lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- $ awk ' {print $0} ' RS= " *, * " ORS= " <<<---n " lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- Записи awk автоматически проанализируются или разделяются на куски, называемые полями .
По умолчанию поля разделяются пробелом (любая строка из одного или нескольких пространств, вкладок или новичков), как слова в строке.
Чтобы ссылаться на поле в программе awk , вы используете знак доллара $ , за которым следует количество поля, которое вы хотите.
Таким образом, $1 относится к первому поле, $2 ко второму и так далее.
Важно : $0 представляет всю запись ввода.
$ awk ' {print $3} ' lorem_ipsum.dat
dolor
erat
orci,
dapibus
dolor
mauris NF - предопределенная переменная, его значение - это количество полей в текущей записи . Итак, $NF будет всегда последним полем записи.
$ awk ' {print NF} ' lorem_ipsum.dat
8
7
10
4
8
10против.
$ awk ' {print $NF} ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
facilisis. FS владеет ценным сепаратором полевого сектора , это значение представляет собой одноразовую строку или regex , которая соответствует разделению между полями в входной записи.
Значение по умолчанию - " " , строка, состоящая из одного пространства. В качестве особого исключения это значение означает, что любая последовательность пространств , вкладок и/или новых линий является единственным сепаратором.
ORS так же, что у нас есть переменная OFS , чтобы управлять тем, как наши поля будут отправлены в выходной поток.
$ cat /etc/group
nobody: * :-2:
nogroup: * :-1:
wheel: * :0:root
daemon: * :1:root
kmem: * :2:root
sys: * :3:root
tty: * :4:root$ awk ' !/^(_|#)/&&$1=$1 ' FS= " : " OFS= " <-> " /etc/group
nobody < - > * < - > - 2< - >
nogroup < - > * < - > - 1< - >
wheel < - > * < - > 0 < - > root
daemon < - > * < - > 1 < - > root
kmem < - > * < - > 2 < - > root
sys < - > * < - > 3 < - > root
tty < - > * < - > 4 < - > root Примечание : ммм ... $1=$1 ???? 3
Имейте в виду записи и поля , теперь были готовы понять наш предыдущий код:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices.Это две полезные встроенные переменные:
NR : Количество входных записей awk обрабатывается с начала выполнения программы.
FNR : текущий номер записи В текущем файле awk сбрасывает FNR на ноль каждый раз, когда запускает новый входной файл.
$ cat n1.dat
one
two$ cat n2.dat
three
four$ awk ' {print NR,FNR,$0} ' n1.dat n2.dat
1 1 one
2 2 two
3 1 three
4 2 fourСтрока формата очень похожа на то, что в ISO c .
Синтаксис:
printf format, item1, item2, …
$ awk ' {printf "%20s <-> %sn",$1,$NF} ' lorem_ipsum.dat
Lorem < - > elit.
Maecenas < - > condimentum.
Nunc < - > ex.
Curabitur < - > tellus.
Lorem < - > elit.
Aliquam < - > ultrices. Вывод из print и printf направлен на стандартный вывод по умолчанию, но мы можем использовать перенаправление для изменения пункта назначения.
Перераспределения в awk написаны так же, как перенаправления в командах Shell , за исключением того, что они написаны в программе awk .
$ awk ' BEGIN{print "hello">"hello.dat"} ' $ awk ' BEGIN{print "world!">>"hello.dat"} ' $ cat hello.dat
hello
world !Также можно отправить вывод в другую программу через трубу :
$ awk ' BEGIN{sh="/bin/sh";print "date"|sh;close(sh)} '
dom nov 13 18:36:25 CET 2016 [Потоки] могут быть указаны на stdin , stdout и stderr .
Например, мы можем написать сообщение об ошибке stderr , как это:
$ awk ' BEGIN{print "Serious error detected!" > "/dev/stderr"} '
Serious error detected ! В Awk массивы являются ассоциативными , каждый из них представляет собой набор пар , индекс - значение , где любой номер или строка может быть индексом.
Декларация не требуется; Новые пары могут быть добавлены в любое время.
| Индекс | Ценить |
|---|---|
| "Перро" | "собака" |
| "Гато" | "кот" |
| "Uno" | "один" |
| 1 | "один" |
| 2 | "два" |
Чтобы направить массив:
array[index-expression]
Назначить значения:
array[index-expression] = value
Чтобы проверить, индексируется ли ключ:
indx in array
Чтобы итерации:
for (var in array) {
var, array[var]
}Используя числовые значения в качестве индексов и сохранение порядка:
for (i = 1 ; i < = max_index ; i++) {
print array[i]
}Полный пример:
$ cat dict.dat
uno one
dos two
tres three
cuatro fourawk ' {dict[$1]=$2}
END{if ("uno" in dict)
print "Yes we have uno in dict!"
if (!("cinco" in dict))
print "No , cinco is not in dict!"
for (esp in dict){
print esp, "->" ,dict[esp]
}
} ' dict.datДает вам:
Yes we have uno in dict !
No , cinco is not in dict !
uno - > one
dos - > two
tres - > three
cuatro - > four gawk не сортирует массивы по умолчанию:
awk ' BEGIN{
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 4 four
0 zero
1 one
2 two
3 threeНо вы можете воспользоваться [Procinfo] для сортировки:
awk ' BEGIN{
PROCINFO["sorted_in"] = "@ind_num_asc"
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 0 zero
1 one
2 two
3 three
4 four gensub(regexp, replacement, how [, target]) : является наиболее продвинутой функцией для замены строк.
И их более простые альтернативы:
gsub(regexp, replacement [, target])
sub(regexp, replacement [, target])
Имея этот файл:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.Мы собираемся поменять положение слов, расположенных слева и справа от каждой запятой.
$ awk ' {print gensub(/([^ ]+)( *, *)([^ ]+)/,
"\3\2\1", "g")} ' lorem.dat
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim euismod, orci id nisi interdum, eget cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Aliquam interdum mauris volutpat nisl et, placerat facilisis. Используя gensub мы захватываем три группы , а затем поменяем заказ.
Чтобы проиллюстрировать более простое действие, давайте изменить точки для запятых :
awk ' $0=gensub(/./, ",", "g") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis, Использование альтернативы gsub :
awk ' gsub(/./, ",") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis,Этот вариант кажется лучше, когда не требуется захват группы .
Другими интересными функциями являются index и substr .
index(in, find)
substr(string, start [, length ])
Работает так:
$ awk ' BEGIN{t="hello-world";print index(t, "-")} '
6$ awk ' BEGIN{t="hello-world";print substr(t,index(t, "-")+1)} '
world Функция split используется для создания массива от строки, делящей его от департамента , она возвращает количество элементов созданного массива.
split(string, array [, fieldsep [, seps ] ])
$ cat passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash$ awk ' n=split($0, a, ":"){print n, a[n]} ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbashПримечание : это можно сделать гораздо более проще:
$ awk ' {print NF,$NF} ' FS= ' : ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbashНапишите пользовательскую функцию довольно проста:
awk ' function test(m)
{
printf "This is a test func, parameter: %sn", m
}
BEGIN{test("param")} 'Дайте нам:
This is a test func, parameter: param Мы также можем вернуть выражение с помощью оператора return :
awk ' function test(m)
{
return sprintf("This is a test func, parameter: %s", m)
}
BEGIN{print test("param")} 'Расположение по параметру - единственный способ сделать локальную переменную внутри функции.
Скалярные значения передаются по значению и массивам по ссылке, поэтому любые изменения, внесенные в массив внутри функции, будут отражены в глобальной области:
awk ' function test(m)
{
m[0] = "new"
}
BEGIN{m[0]=1
test(m)
exit
}
END{print m[0]} 'Выходы:
newНаши проблемы :
01. Последнее слово записи.
02. Замена записи.
03. Поместите полуколон в конце каждой записи.
04. Поместите запятую между каждым словом.
05. Все вместе?
06. Перенаправление нечетных записей в файл и даже один в другой.
07. Учитывая файл пароля. Получите отсутствующее поле.
08. Обмена поля.
09. Traceroute Hacking.
10. Где мои дети?
11. Агрегация данных.
12. Записи между двумя шаблонами.
13. Полевое преобразование.
14. Записи в столбцах.
15. Обработка файлов FASTA.
16. Сложная отчетность.
17. Файлы Сторонник.
18. Passwd и Group.
19. Пользовательские соединения.
20. Среднее время безотказной работы.
Имея этот исходный файл:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' {print $(NF-1)} ' lorem.dat
adipiscing
consectetur
cursus
dapibus
adipiscing
neque Не слишком много, чтобы объяснить здесь, NF хранит количество полей в текущей записи, поэтому NF-1 указывает на поле до последнего, а $(NF-1) станет его стоимостью.
Наша задача, замена записи файла, третья строка должна стать:
This not latin
Ничего более простого, просто играйте вокруг NR ( количество записей ).
Код:
$ awk ' NR==3{print "This is not latin";next}{print} ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. Альтернативное решение, чтобы избежать next оператора: назначьте новую строку полной записи $0 .
Пример:
$ awk ' NR==3{$0="This is not latin"}1 ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' 1 ' ORS= " ;n " lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Maecenas pellentesque erat vel tortor consectetur condimentum. ;
Nunc enim orci, euismod id nisi eget, interdum cursus ex. ;
Curabitur a dapibus tellus. ;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Aliquam interdum mauris volutpat nisl placerat, et facilisis neque ultrices. ; Поскольку RS по умолчанию является линией разрыва Unix n нам просто нужно префикс полуколон к OFS выходной записи.
1 ? 4
$ awk ' {$1=$1}1 ' OFS= ' , ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum.
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex.
Curabitur,a,dapibus,tellus.
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. Наиболее важной частью этого кода является то, как он заставляет рекордную реконструкцию с $1=$1 за текущую стоимость OFS .
$ awk ' {$1=$1}1 ' OFS= ' , ' ORS= ' ;n ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum. ;
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex. ;
Curabitur,a,dapibus,tellus. ;
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. ; Как просто игра с выходными vars: OFS и ORS .
Начнем с окончательного решения:
$ awk ' NR%2{print > "even.dat";next}
{print > "odd.dat"} ' lorem.dat$ cat even.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Lorem ipsum dolor sit amet, consectetur adipiscing elit$ cat odd.dat
Maecenas pellentesque erat vel tortor consectetur condimentum.
Curabitur a dapibus tellus.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. Функция [modulo] ( % ) находит остаток после деления для текущего числа записей NR разделенного на два:
$ awk ' {print NR%2} ' lorem.dat
1
0
1
0
1
0 Насколько нам сейчас, в awk 1 истинно и 0 False . Мы перенаправляем наш выход, оценивая этот факт.
next требуется особое внимание, он заставляет awk немедленно прекратить текущий процесс записи и передать следующему.
Таким образом мы ускользаем от двойного состояния, которое будет выглядеть так:
awk ' NR % 2{print > "even.dat"}
!NR % 2{print > "odd.dat"} ' lorem.dat$ cat /etc/passwd
jd001:x:1032:666:Javier Diaz::/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez::/bin/rbash
jp003:x:1000:666:Jose Perez::/bin/bash
ms004:x:8051:668:Maria Saenz::/bin/rbash
rc005:x:6550:668:Rosa Camacho::/bin/rbash Давайте предположим, что домашний каталог путем префикса фиксированной строки "/home/" на имя пользователя :
$ awk ' $6="/home/"$1 ' FS= ' : ' OFS= ' : ' /etc/passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbashНашим первым шагом должен быть рассмотрение полевого сепаратора, толстой кишки, как для ввода, так и для вывода.
Тогда нам нужно найти позицию полевого поля 6 для этого примера.
Наконец, мы составляем необходимое значение, используя заданную строку и вход пользователя, хранящийся в первом поле.
print не требуется, потому что возвращаемое значение назначения в размере $6 всегда будет истинным , а awk по умолчанию - это напечатана затронутая запись.
Наша цель: последнее поле должно стать первым и первым стать последним.
Окончательный код:
$ awk -F : ' {last=$1;$1=$NF;$NF=last}1 ' FS= " : " OFS= ' : ' /etc/passwd
/bin/rbash:x:1032:666:Javier Diaz:/home/jd001:jd001
/bin/rbash:x:8050:668:Alejandro Gonzalez:/home/ag002:ag002
/bin/bash:x:1000:666:Jose Perez:/home/jp003:jp003
/bin/rbash:x:8051:668:Maria Saenz:/home/ms004:ms004
/bin/rbash:x:6550:668:Rosa Camacho:/home/rc005:rc005 Мы играем с промежуточной переменной, используемой для хранения первого значения поля, мы обмениваем его значение на последнюю, наконец, мы назначаем last переменную $NF ( $NF=last ).
Имея этот вывод:
$ traceroute -q 1 google.com 2> /dev/null
1 hitronhub.home (192.168.1.1) 5.578 ms
2 217.217.0.1.dyn.user.ono.com (217.217.0.1) 9.732 ms
3 10.127.54.181 (10.127.54.181) 10.198 ms
4 62.42.228.62.static.user.ono.com (62.42.228.62) 35.519 ms
5 72.14.235.20 (72.14.235.20) 26.003 ms
6 216.239.50.133 (216.239.50.133) 25.678 ms
7 mad01s24-in-f14.1e100.net (216.58.211.238) 25.019 msНам нужно вычислить пакет , путешествуя по общему времени.
$ traceroute -q 1 google.com 2> /dev/null |
awk ' {total+=$(NF-1)}
END{print "Total ms: "total} '
Total ms: 153.424Поскольку не указано условия, действие выполняется для всех записей .
total+=$(NF-1) : total переменная используется для накопления стоимости каждого последующего полевого поля $(NF-1) .
Наконец, мы используем правило END , чтобы показать окончательное total значение.
Наша работа: Получите наши зависимые от shell процессы.
$ echo $$
51026Первое : запустите фоновые процессы.
$ sleep 10 & sleep 15 & sleep 20 &
[1] 86751
[2] 86752
[3] 86753 Используя ps Utility , awk будет искать третье поле, известное как PPID .
Примечание . Мы используем -v для установки PPID VAR до начала выполнения программы.
$ ps -ef | awk -v ppid= $$ ' $3==ppid '
501 86751 51026 0 7:57PM ttys001 0:00.00 sleep 10
501 86752 51026 0 7:57PM ttys001 0:00.00 sleep 15
501 86753 51026 0 7:57PM ttys001 0:00.00 sleep 20
0 86754 51026 0 7:57PM ttys001 0:00.00 ps -ef
501 86755 51026 0 7:57PM ttys001 0:00.00 awk $3 ==51026Нам просто нужны сна :
$ ps -ef | awk -v ppid= $$ ' $3 == ppid && /slee[p]/
{print $2" -> "$5} '
86751 - > 7:57PM
86752 - > 7:57PM
86753 - > 7:57PM Решению требуется новое условие, чтобы добавить: найдите шаблон сна в нашей текущей записи /slee[p]/ .
Запускаемое действие будет состоять в том, чтобы напечатать второе поле $2 с подставками для PID и пятой $5 , марки времени .
Имея этот файл:
$ cat ips.dat
IP BYTES
81.220.49.127 328
81.220.49.127 328
81.220.49.127 329
81.220.49.127 367
81.220.49.127 5302
81.226.10.238 328
81.227.128.93 84700 Наша задача - вычислить, сколько байтов на IP обрабатывается.
$ awk ' NR>1{ips[$1]+=$2}
END{for (ip in ips){print ip, ips[ip]}} ' ips.dat
81.220.49.127 6654
81.227.128.93 84700
81.226.10.238 328Куча вещей здесь, чтобы объяснить.
NR>1{ips[$1]+=$2} : действие ips[$1]+=$2 выполняется только тогда, когда текущий номер записи больше одного NR>1 . Это необходимо, чтобы избежать заголовка.
ips - это массив, индексированный по значению IP (поле $1 ), для каждого ключа мы собираемся накапливать в значении второго поля.
Обратите внимание на важный факт , если ключ не присутствует в массиве , awk добавляет в структуру новый элемент, в противном случае собирается обновить предыдущее значение, указанное этим ключом (как в нашем примере).
END правило просто используется для итерации массива по индексам и значениям.
Этот код может быть переписан по -разному по -разному, чтобы избежать использования массивов и сохранить заказ, пользующийся сортированным файлом IPS :
awk ' NR==1{next}
lip && lip != $1{print lip,sum;sum=0}
{sum+=$2;lip=$1}
END{print lip,sum} ' ips.dat
81.220.49.127 6654
81.226.10.238 328
81.227.128.93 84700 NR==1{next} : обойти заголовок.
lip && lip != $1{print lip,sum;sum=0} : здесь мы используем var с именем lip ( Last-IP ). lip && lip != $1 , когда lip не является нулевой , и его значение не равна первому поле (которое удерживает текущий IP), запускаемое действие будет заключаться в печати lip и sum общего количества байтов для последнего IP. Затем мы инициализируем это sum=0 .
Хитрость ясно, каждый раз, когда IP ( $1 ) изменения мы показываем статистику предыдущего.
{sum+=$2;lip=$1} : чтобы обновить счетчик байтов sum+=$2 и назначить текущий IP на lip : lip=$1 . Это последний шаг нашей обработки записей.
END блок используется для печати ожидающих значений .
Этот код сохраняет порядок, но , на мой взгляд , это происходит за счет значительно повышенной сложности.
Наша задача - две извлечения линий между OUTPUT и END .
$ cat pat.dat
test -3
test -2
test -1
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
END
test 1
test 2
test 3 Это классический пример, используемый для иллюстрации того, как сопоставление схемы работает в awk и его ассоциированных действиях, которые я посвятил полным [post].
$ awk ' /END/{flag=0}flag;/OUTPUT/{flag=1} ' pat.dat
top 2
bottom 1
left 0
right 0
page 66 Он основан на значении переменной flag , он будет истинным ( 1 ), когда будет найден OUTPUT начального шаблона и false ( 0 ), когда достигнут END тег .
Чтобы избежать дополнительного шага, порядок действий очень важен , если мы следуем по логической последовательности :
$ awk ' /OUTPUT/{flag=1}flag;/END/{flag=0} ' pat.dat
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
ENDТеги шаблона показаны через выход.
Причина: после того, как OUTPUT шаблон найден, флаг активируется, так как следующее действие зависит от этого флага, запись напечатана.
Мы можем избежать этого поведения , размещая активацию флага как последний шаг потока.
Предположим, этот файл:
$ cat space.dat
10.80 kb
60.08 kb
35.40 kb
2.20 MB
1.10 MB
40.80 kb
3.15 MB
20.50 kbНаша задача будет заключаться в расчете наших записей общего веса в мега -байтах :
$ awk ' {total+= $1 / ($2=="kb" ? 1024: 1)}
END{print total} ' space.dat
6.61365Чтобы понять, как это работает, одна концепция должна быть ясной, [тройной] оператор (предмет старого поста).
total будет использоваться для накопления делителя первого поля $1 США на $2 США, которые будут содержать стоимость, указанную тройным оператором : 1024 , когда $2 равны kb и 1 если не требуется преобразование.
Наконец, мы печатаем total значение в END блоке.
Первоначальный источник:
$ cat group.dat
string1
string2
string3
string4
string5
string6
string8Наша миссия состоит в том, чтобы группировать записи в блоках трех столбцов, таких как это:
string1 string2 string3
string4 string5 string6
string8 Это может показаться сложным, но становится намного проще, если мы понимаем, как использовать сепаратор поля вывода OFS
$ awk ' ORS = NR%3 ? FS : RS; END{print "n"} ' group.dat
string1 string2 string3
string4 string5 string6
string8 Если мы установим ORS на пустой символ, значение по умолчанию FS , весь вывод станет одной строкой:
$ awk ' ORS=FS; END{print "n"} ' group.dat
string1 string2 string3 string4 string5 string6 string7 ORS = NR%3 ? FS : RS : Наконец, мы используем тройного оператора (объясняется незадолго до), чтобы оценить [Modulo] NR%3 результат разделения текущего номера поля NR на три.
Если оставшаяся часть верна, ORS становится FS , пустое пространство, в противном случае будет назначено значение по умолчанию RS , разрыв строки Unix n .
В биоинформатике [FASTA] является текстовым форматом файла.
Имея следующий пример:
$ cat fasta.dat
> header1
CGCTCTCTCCATCTCTCTACCCTCTCCCTCTCTCTCGGATAGCTAGCTCTTCTTCCTCCT
TCCTCCGTTTGGATCAGACGAGAGGGTATGTAGTGGTGCACCACGAGTTGGTGAAGC
> header2
GGT
> header3
TTATGATНам нужна общая длина каждой последовательности и окончательное резюме .
Должен выглядеть так:
> header1
117
> header2
3
> header3
7
3 sequences, total length 127 awk - идеальный инструмент для этого усилия по отчетности , для этого примера мы будем использовать:
awk ' /^>/ { if (seqlen) {
print seqlen
}
print
seqtotal+=seqlen
seqlen=0
seq+=1
next
}
{
seqlen += length($0)
}
END{print seqlen
print seq" sequences, total length " seqtotal+seqlen
} ' fasta.dat
Первое действие связано с обнаружением заголовка /^>/ , это потому, что все заголовки звезд с > характером.
Когда seqlen не является нулевым, его значение, которое удерживает предыдущую длину последовательности, напечатана к STDOUT, прикрепленному к новому заголовку. seqtotal обновляется и инициализируется seqlen , чтобы обслуживать следующую последовательность. Наконец, мы нарушаем дальнейшую обработку записи со next .
Второе действие {seqlen += length($0)} используется для обновления seqlen , суммирующего общую длину записи.
Цель END правила состоит в том, чтобы показать бездомную последовательность и общие.
Хитрость здесь состоит в том, чтобы напечатать предыдущую длину последовательности , когда мы нашли новый заголовок .
Когда мы обрабатываем первую запись, seqlen не имеет значения, поэтому мы пропускаем визуализацию.
Источник:
$ cat report.dat
snaps1: Counter: 4966
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 0
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.test.attributes
snaps1: Counter: 5660
Opens: Counter: 37283
Instance: s.1.aps.userDatabase.mount275000.attributes Наша обязанность : Создайте отчет для визуализации snaps и instance , но только тогда, когда первая тег -метка Snap больше, чем нуль .
Ожидаемый выход:
snaps1: Counter: 4966
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 5660
Instance: s.1.aps.userDatabase.mount275000.attributesМы снова играем вокруг узоров и флагов :
awk ' {$1=$1}
/snaps1/ && $NF>0{print;f=1}
f && /Instance/ {print;f=0} ' report.dat Для каждой записи первое действие выполняется , оно заставляет awk перестроить всю запись , используя текущие значения для OFS 3 .
Этот трюк позволяет нам преобразовать несколько пространственных сепараторов в один символ , значение по умолчанию для сепаратора поля вывода.
Посмотрим:
$ awk ' 1 ' text.dat
one two
three four$ awk ' $1=$1 ' text.dat
one two
three four Второе действие запускается при обнаружении шаблона, а последнее поле больше нуля /snaps1/ && $NF>0 .
awk печатает запись и назначает истинное значение print;f=1 .
Последний шаг: когда флаг является истинной и рисунком экземпляра в строке f && /Instance/ , Покажите линию и деактивируйте флаг: print;f=0 .
Предположим, два архива:
$ cat join1.dat
3.5 22
5. 23
4.2 42
4.5 44$ cat join2.dat
3.5
3.7
5.
6.5 Нам нужны записи с первого join1.dat , когда первые поля находятся во втором join2.dat .
Вывод должен быть:
3.5 22
5. 23Конечно, мы можем использовать Unix Join Join , но нам нужно сортировать первый файл:
$ join <( sort join1.dat ) join2.dat
3.5 22
5. 23 Не нужно в awk :
$ awk ' NR == FNR{a[$1];next}
$1 in a ' join2.dat join1.datДавайте изучим фильтры и действия:
NR == FNR : номер записи , равный номеру файла записи, означает, что мы обрабатываем первый файл, проанализированный на awk : join2.dat .
Действие пары a[$1];next будет добавить новое значение пустоты к массиву, индексированному первым полем. next заявление нарушит обработку записей и передаст поток следующему .
Для второго действия NR != FNR применяется неявно и влияет только на join1.dat , второе условие составляет $1 in a , которое будет верно, когда первое поле join1.dat является ключом массива.
Это Unix Classics :
$ cat /etc/group
dba:x:001:
netadmin:x:002:$ cat /etc/passwd
jd001:x:1032:001:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:002:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:001:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:002:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:002:Rosa Camacho:/home/rc005:/bin/rbashНаша цель, такой отчет:
d001:dba
ag002:netadmin
jp003:dba
ms004:netadmin
rc005:netadminНам нужен несколько файлов поток , как мы изучали в нашем последнем примере:
$ awk -F : ' NR == FNR{g[$3]=$1;next}
$4 in g{print $1""FS""g[$4]} ' /etc/group /etc/passwd $3 $1 / NR == FNR g[$3]=$1 /etc/group / Наконец, мы нарушаем дальнейшую обработку записи со next .
Второе условие будет нацелено только /etc/passwd records, когда четвертое поле $4 ( идентификатор группы ) присутствует в массиве $4 in g , мы напечатаем логин и значение, указанное массивом , индексированным группой ID g[$4] , SO: print $1""FS""g[$4] .
Пример вывода утилиты пользователей:
$ users
negan rick bart klashxx klashxx ironman ironman ironmanМы собираемся подсчитывать входы на одного пользователя.
$ users | awk ' {a[$1]++}
END{for (i in a){print i,a[i]}} ' RS= ' + '
rick 1
bart 1
ironman 3
negan 1
klashxx 2Действие выполняется для всех записей.
a[$1]++ : это счетчик , для каждого пользователя $1 Он увеличивает заостренное значение (нежидиализованные VAR имеют числовое значение нулевым значением).
В END блоке отмечает массив ключом и сохраненным значением, чтобы представить результаты.
Типичный выход:
$ uptime
11:08:51 up 121 days, 13:09, 10 users, load average: 9.12, 14.85, 20.84Как мы можем получить общее среднее среднее значение ?
$ uptime | awk ' {printf "Load average mean: %0.2fn",
($(NF-2)+$(NF-1)+$(NF))/3 } ' FS= ' (:|,) + '
Load average mean: 14.94Вот новая техника.
Мы используем [regex] в качестве сепаратора поля (:|,) + , поэтому FS может быть толстой кишкой и запятой, за которой следует ноль или более пустые пространства.
Нам просто нужны последние три поля , чтобы выполнить необходимую арифметику, затем мы используем printf , прикрепленный к надлежащей маске .
Если вы все еще здесь, спасибо !!
С моей точки зрения, awk - это недооцененный язык, который нуждается в большой любви ❤.
Если вы голодны для получения дополнительной информации, дайте мне знать это в разделе комментариев Bellow, и я рассмотрю вторую часть, чтобы закончить мою миссию ... сдержать вас до смерти.
Счастливого кодирования!
[Руководство по цитированию оболочки Unix] [Цитативная гибель]. ↩
[Википедия на трубопроводах] [трубы]. ↩
Есть моменты, когда удобно заставить awk перестроить всю запись, используя текущие значения FS и OFS .
Для этого мы используем, казалось бы, безобидное назначение: $1 = $1 ↩ ↩ 2
Быстрый ответ, это просто ярлык , чтобы избежать использования оператора печати.
В awk , когда условие соответствует, действие по умолчанию - это печатать входную строку.
$ echo "test" |awk '1'
Эквивалентно:
echo "test"|awk '1==1'
echo "test"|awk '{if (1==1){print}}'
Это потому, что 1 будет всегда [правдой]. ↩