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

Если вам интересно, название AWK — это просто инициалы трех его создателей: Ахо, Вайнбергера и Кернигана — да, этого Кернигана.

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

Предположим, вам нужно найти шаблон в текстовом файле, распечатать строку, содержащую его, а также распечатать n-ю строку после этого.

Вот один из способов.

Прежде всего, вот входной текстовый файл, который я ищу. Мы назовем его x.txt

AAAA BBBB CCCC DDDD
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8

Допустим, я хочу найти строку, содержащую текст BBBB, распечатать ее, а также распечатать 3-ю строку после этой строки, т.е. Line 4.

Итак, мы хотим, чтобы это было результатом:

AAAA BBBB CCCC DDDD
Line 4

Следующая команда AWK сделает это.

awk "/BBBB/{i=1;print}!i{next}{if(i++==4){print}}" x.txt

Вы можете немного расширить это, изменив строку if(i++==4). Допустим, вам нужна целевая строка плюс строки 3, 4 и 5 после нее.

e.g

AAAA BBBB CCCC DDDD
Line 3
Line 4
Line 5

Это сделает это.

awk "/BBBB/{i=1;print}!i{next}{if(i++>=3 && i <= 6){print}}" x.txt

Теперь, что насчет оборотной стороны этого? Вы хотите распечатать строку, совпадающую с шаблоном, и одну или несколько строк перед перед ней, скажем, за 3 строки до «Строки 8».

awk "/Line 8/{for(i=1;i<=x;)print a[i++];print}{for(i=1;i<x;i++)a[i]=a[i+1];a[x]=$0;}" x=3 x.txt

Вышеупомянутое будет распечатано

Line 5
Line 6
Line 7
Line 8​​

Вот еще один полезный скрипт. Допустим, у вас есть два текстовых файла, и вы хотите сопоставить записи в обоих по ключу, а затем заменить каждую строку в файле2 соответствующей строкой с ключом из файла1. Пример поможет проиллюстрировать ситуацию.

Вам нужно заменить всю строку в файле 2.txt на основе ключа в файле 1.txt. В целях именования мы будем называть все до знака «=» ключа записи.

file1.txt
=========
ui_home=/export/appl/website/${ui.root}
java_home=/export/appl/java/ssss
domain.host.list=server-1,server-2
domain.server.cluster.list=server-1:cluster1,server-2:cluster2
runtime=/export/appl/website/runtime
ldap.provider.url=ldap://ldapserver:280


file2.txt
========
ui_home=/export/appl/ui/${test}
java_home=/export/appl/java/zzzzz
domain.host.list=server-10,server-12
domain.server.cluster.list=server-10:cluster1,server-12:cluster2
runtime=/export/appl/website/runtime
ldap.provider.url=ldap://ldapserver:480
ai.home=/export/appl/ddss/shss

Результат, который мы хотим, показан ниже

new-file2.txt
=============
ui_home=/export/appl/website/${ui.root}
java_home=/export/appl/java/ssss
domain.host.list=server-1,server-2
domain.server.cluster.list=server-1:cluster1,server-2:cluster2
runtime=/export/appl/website/runtime
ldap.provider.url=ldap://ldapserver:280
ai.home=/export/appl/ddss/shss

Везде, где есть совпадающий «ключ записи» между файлом1 и файлом2, соответствующая запись файла2, содержащая этот ключ, заменяется соответствующей записью файла1. При отсутствии соответствующего ключа данные остаются неизменными.

Следующий awk-скрипт сделает это.

$ awk -F = -v OFS== 'FNR==NR{k[$1]=$2;next}$1 in k{$2=k[$1]}1' file1.txt file2.txt > new-file2.txt

И вот объяснение каждой из частей:

awk 
-F =         # set FS ( Field Separator ) to "=" so automatically splits lines to key ( $1 ) - value ( $2 ) pairs
-v OFS==     # set OFS ( Output Field Separator ) to "=" so automatically place it between the fields on output
'
FNR == NR {  # FNR ( File Number of Records ) and NR ( Number of Records ) are equal only while processing the 1st input file
k[$1] = $2   # store the key - value pair in array k
next         # jump to processing the next input record ( skip the rest of the code - it is for processing the 2nd input file )
}
$1 in k {    # current key has an entry in array k
$2 = k[$1]   # replace the current value with the matching one stored in array k
}
1            # always perform default action ( print the current record )
' 
file1.txt file2.txt > new-file2.txt  # process our two input files and create our new output file

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

bigfile.txt
===========

Line 1|2|some other stuff
Line 2|1|blah blah
Line 3|8|blah blah
Line 4|2|this is line 4
Line 5|8|this is line 5
Line 6|1|this is line 6

Вам нужно создать отдельные файлы, fileN.txt, где значение N основано на числовом значении во втором поле. В этом примере вы хотите создать файлы file1.txt, file2.txt и file8.txt. Кроме того, содержимое каждого созданного файла должно соответствовать строкам в файле большего размера. Вот один из способов сделать это.

$ awk -F"|" '{fname="file"$2".txt"} {print >fname}' bigfile.txt
$
$ cat file1.txt

Line 2|1|blah blah
Line 6|1|this is line 6
$
$ cat file2.txt
Line 1|2|some other stuff
Line 4|2|this is line 4
$
$ cat file8.txt
Line 3|8|blah blah
Line 5|8|this is line 5

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

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