вы также можете попробовать ssconvert
сопутствующий инструмент конвертера gnumeric
ssconvert in.xlsx out.xls
(как обычно, см. man ssconvert
)
Для нормальных случаев это нормально. Если входной файл очень продвинутый в обоих конвертерах (libreoffice и gnumeric), некоторые детали могут быть потеряны.
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
здесь указывает на " начальный" номер строки после строки шаблона
Попробуйте разбить операцию на несколько шагов, каждый из которых можно выполнить, используя разные программы с их базовыми функциями.
Например, сначала найдите шаблон /z ~/
и напечатайте следующие 6 строк (grep -A6 "z ~"
), затем напечатайте 4-ю, 5-ю и 6-ю строки. столбцы. Наконец, отфильтруйте только те, в которых есть цифра, чтобы линия между совпадением шаблона и цифрами была отброшена.
Чтобы обернуть его в команду:
grep -A6 "z ~" file | awk '{ print $4, $5, $6 }' | grep -E "[[:digit:]]"`
/~ ~/
. Все, что снаружи, удаляется. \n
в начале 4-го поля и еще один в конце 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
Вы можете пересмотреть свою логику. Вместо подсчета строк здесь кажется более надежным полностью основывать извлечение на шаблонах самих линий. Может быть, этот пригодится:
awk '/^~ [A-Z]/' t.txt |cut -f 4-6 -d " "
Значение :Извлечь только те строки, которые начинаются с " ~" и где третий символ является заглавной буквой. Затем передайте вывод awk через cut, извлекая только поля с 4 по 6 (, начиная отсчет с 1 )и устанавливая разделитель на один пробел.
Самым простым решением было бы просто добавить еще одну 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
Для сопоставления этих строк достаточно шаблона /^~ [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
, но это добавляет дополнительные нули к некоторым числам.