Вопрос AWK: напечатать N строк, начиная с третьей строки после данного / pattern /

вы также можете попробовать ssconvert сопутствующий инструмент конвертера gnumeric

ssconvert in.xlsx out.xls

(как обычно, см. man ssconvert )

Для нормальных случаев это нормально. Если входной файл очень продвинутый в обоих конвертерах (libreoffice и gnumeric), некоторые детали могут быть потеряны.

4
21.08.2018, 02:36
6 ответов

awkрешение:

awk '/z ~/{ n=NR+2 }n && n<=NR && NR<(n+5){ print $4,$5,$6 }' file | column -t

Вывод:

0.00781   0.00108   0.00038
0.01271   -0.01507  0.02839
-0.05015  -0.01803  0.01588
0.01733   0.03089   -0.04611
0.01230   0.00114   0.00147

  • NR- номер текущей записи

  • n=NR+2- nздесь указывает на " начальный" номер строки после строки шаблона

6
27.01.2020, 20:46

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

Например, сначала найдите шаблон /z ~/ и напечатайте следующие 6 строк (grep -A6 "z ~"), затем напечатайте 4-ю, 5-ю и 6-ю строки. столбцы. Наконец, отфильтруйте только те, в которых есть цифра, чтобы линия между совпадением шаблона и цифрами была отброшена.

Чтобы обернуть его в команду:

grep -A6 "z ~" file | awk '{ print $4, $5, $6 }' | grep -E "[[:digit:]]"`
2
27.01.2020, 20:46

Работает

  1. Сначала мы выделяем диапазон между строками /~ ~/. Все, что снаружи, удаляется.
  2. Сами выбросы диапазона также удаляются.
  3. Теперь у нас есть нужные строки для работы: в них мы размещаем маркер \n в начале 4-го поля и еще один в конце 6-го.
  4. Наконец, мы удаляем все, что находится за пределами этих маркеров, и остаются 4-е, 5-е и 6-е поля + их промежуточные пробелы (без изменений).

sed -ne '
   /~ ~/,//!d
   //d
   s/[^[:space:]]\{1,\}/&\n/6
   s/[^[:space:]]\{1,\}/\n&/4
   s/.*\n\(.*\)\n.*/\1/p
' yourfile

Результаты

0.00781      0.00108      0.00038
0.01271     -0.01507      0.02839
-0.05015     -0.01803      0.01588
0.01733      0.03089     -0.04611
0.01230      0.00114      0.00147
3
27.01.2020, 20:46

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

 awk '/^~ [A-Z]/' t.txt |cut -f 4-6 -d " "

Значение :Извлечь только те строки, которые начинаются с " ~" и где третий символ является заглавной буквой. Затем передайте вывод awk через cut, извлекая только поля с 4 по 6 (, начиная отсчет с 1 )и устанавливая разделитель на один пробел.

0
27.01.2020, 20:46

Самым простым решением было бы просто добавить еще одну getlineи тогда получить 5 строк вместо 6:

$ awk '/z ~/ {getline;for(i=1; i<=5; i++) {getline; print $4, $5, $6}}' file
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147

Лично я бы сделал это немного по-другому:

$ awk '/z ~/{f=2;} /~ ~/{f--}; (f==1 && NF>5){print $4, $5, $6} ' file
0.00781 0.00108 0.00038
0.01271 -0.01507 0.02839
-0.05015 -0.01803 0.01588
0.01733 0.03089 -0.04611
0.01230 0.00114 0.00147

Идея состоит в том, чтобы установить флаг (переменной f)на 2в строке, соответствующей z ~, и уменьшать ее значение на единицу каждый раз, когда мы находим строку, соответствующую ~ ~. Затем мы печатаем поля 4, 5 и 6 только в строках, где f— это1и , которые имеют не менее 5 полей.

Для обоих примеров, чтобы получить красивую печать, вы можете использовать -vOFS="\t"или даже лучшеprintf:

$ awk '/z ~/{f=2;} /~ ~/{f--}; (f==1 && NF>5){printf "%10s%10s%10s\n", $4, $5, $6} ' file
   0.00781   0.00108   0.00038
   0.01271  -0.01507   0.02839
  -0.05015  -0.01803   0.01588
   0.01733   0.03089  -0.04611
   0.01230   0.00114   0.00147
4
27.01.2020, 20:46

Для сопоставления этих строк достаточно шаблона /^~ [A-Z]/и для каждой печати соответствующих полей 4, 5 и 6.

Версия Awk будет:

$ awk '/^~ [A-Z]/{printf("%-8s\t%-8s\t%-8s\n",$4,$5,$6)}' input.txt
0.00781     0.00108     0.00038 
0.01271     -0.01507    0.02839 
-0.05015    -0.01803    0.01588 
0.01733     0.03089     -0.04611
0.01230     0.00114     0.00147 

И перевод того же на perl:

$ perl -ane 'printf("%-8s\t%-8s\t%-8s\n",$F[3],$F[4],$F[5]) if /^~ [A-Z]/' input.txt                                     
0.00781     0.00108     0.00038 
0.01271     -0.01507    0.02839 
-0.05015    -0.01803    0.01588 
0.01733     0.03089     -0.04611
0.01230     0.00114     0.00147 

Обратите внимание, что здесь мы используем функцию printf()с флагами выравнивания по левому краю -%-8sдля правильного форматирования.

Альтернативным способом может быть обработка желаемых чисел как чисел с плавающей запятой и использование спецификатора %fвместо %-8s, но это добавляет дополнительные нули к некоторым числам.

1
27.01.2020, 20:46

Теги

Похожие вопросы