Советы по awk


Использование сокращений

Конструкцию, используемую для вывода строк соответствующих заданной маске:

awk '{if ($0 ~ /pattern/) print $0}'

можно сократить до

awk '/pattern/'

Условие в awk может быть задано вне скобок, т.е. получаем:

awk '$0 ~ /pattern/ {print $0}'

По умолчанию, действия производятся со всей строкой, $0 можно не указывать:

awk '/pattern/ {print}'

print — является действием по умолчанию, его тоже можно не указывать:

awk '/pattern/'

Для вывода значения первого столбца строки, в которой присутствует маска LEGO:

awk '/LEGO/ {print $1}'

Для вывода значения первого столбца строки, во втором столбце которой присутствует маска LEGO:

awk '$2 ~ /LEGO/ {print $1}'

Для замены слова LIGO на LEGO и вывода только измененных строк можно использовать:

awk '{if(sub(/LIGO/,"LEGO")){print}}'

Но если нужно выводить все строки (как sed ‘s/LIGO/LEGO/’), конструкцию можно упростить (1 — true для всех строк):

awk '{sub(/LIGO/,"LEGO")}1'

Вывести все строки, за исключением каждой шестой:

awk 'NR % 6'

Вывести строки, начиная с 6 (как tail -n +6 или sed ‘1,5d’):

awk 'NR > 5'

Вывести строки, в которых значение второго столбца равно foo:

awk '$2 == "foo"'

Вывести строки, в которых 6 и более столбцов:

awk 'NF >= 6'

Вывести строки, в которых есть слова foo и bar:

awk '/foo/ && /bar/'

Вывести строки, в которых есть слово foo, но нет bar:

awk '/foo/ && !/bar/'

Вывести строки, в которых есть слова foo или bar (как grep -e ‘foo’ -e ‘bar’):

awk '/foo/ || /bar/'

Вывести все непустые строки:

awk 'NF'

Вывести все строки, удалив содержимое последнего столбца:

awk 'NF--'

Вывести номера строк перед содержимым:

awk '$0 = NR" "$0'

Заменим команды (пропускаем 1 строку, фильтруем строки с foo и заменяем foo на bar, затем переводим в верхний регистр и выводим значение второго столбца):

cat test.txt | head -n +1 | grep foo | sed 's/foo/bar/' | tr '[a-z]' '[A-Z]' | cut -d ' ' -f 2

аналогичной конструкцией на awk:

cat test.txt | awk 'NR>1 && /foo/{sub(/foo/,"bar"); print toupper($2)}'

Использование диапазонов

Вывести группу строк, начиная со строки, в которой есть foo, и заканчивая строкой, в которой есть bar:

awk '/foo/,/bar/'

Исключив из вывода строки с вхождением заданных масок:

awk '/foo/,/bar/{if (!/foo/ && !/bar/)print}'

Более оптимальный вариант:

awk '/bar/{p=0};p;/foo/{p=1}'

Исключить только строку с завершающим вхождением (bar)

awk '/bar/{p=0} /foo/{p=1} p'

Исключить только строку с начальным вхождением (foo)

awk 'p; /bar/{p=0} /foo/{p=1}'

Разбиение файла по шаблонам

Имеется файл (file), в котором группы строк разделены шаблонами FOO1,FOO2 и т.д. Необходимо записать данные, находящиеся между метками FOO в разные файлы, соответствующие указанным в FOO номерам.

awk -v n=1 '/^FOO[0-9]*/{close("out"n);n++;next} {print > "out"n}' file

В GNU Awk можно сделать так:

LC_ALL=C gawk -v RS='FOO[0-9]*\n' -v ORS= '{print > "out"NR}' file

Парсинг CSV

По умолчанию в качестве разделителя используются пробел и табуляция. Чтобы определить иной разделитель, например запятую, нужно использовать FS=’,’ или опцию «-F».
В качестве параметра может быть задано регулярное выражение, например:

FS='^ *| *, *| *$'

Но для разбора CSV это не подойдет, так как пробелы могут присутствовать и внутри строк, поэтому проще вырезать лидирующие пробелы перед и после запятой:

FS=','
for(i=1;i<=NF;i++){
gsub(/^ *| *$/,"",$i);
print "Field " i " is " $i;
}

Если в CSV данные помещены в кавычки, например «field1″,»field2», то подойдет такой скрипт:

FS=','
for(i=1;i<=NF;i++){
gsub(/^ *"|" *$/,"",$i);
print "Field " i " is " $i;
}

Но скрипт придется усовершенствовать для разбора полей вида:

field1, «field2,with,commas» , field3 , «field4,foo»

$0=$0",";
while($0) {
match($0,/[^,]*,| *"[^"]*" *,/);
sf=f=substr($0,RSTART,RLENGTH);
gsub(/^ *"?|"? *,$/,"",f);
print "Field " ++c " is " f;
sub(sf,"");
}

Проверка IPv4 адреса

awk -F '[.]' 'function ok(n) {
return (n ~ /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/)
}
{exit (ok($1) && ok($2) && ok($3) && ok($4))}'

Сравнение двух файлов

Вывод всех дублирующихся строк из двух неотсортированных файлах file1 и file2:

awk '!($0 in a) {c++;a[$0]} END {exit(c==NR/2?0:1)}' file1 file2

Вывод только выделенных блоков текста

Например, чтобы показать из файла с текстом только текст, отмеченный как =текст= можно использовать:

awk -v RS='=' '!(NR%2)'

с форматированием переносов строк:

awk -v RS='=' '!(NR%2){gsub(/\n/," ");print}'

Полезные ссылки по теме:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *