Как использовать grep / awk / sed, чтобы изолировать часть файла между разделителями, потенциально пересекая строки - PullRequest
1 голос
/ 28 апреля 2019

Я пытаюсь получить определенную часть выходного файла, используя скрипт bash, но я не знаю, как это сделать.Прежде всего, мне нужны данные между \HF= и первым вхождением другого \.. Значения разделяются запятой, но иногда между ними возникают разрывы строк.Мне нужно grep всех этих значений и отправить их в новый файл, содержащий только их, по одному на строку.

Пример выходного файла, который у меня есть:

...\HF=-56.876868,-56.2343,-42.
343,-67.3453423,-85.74656,-
45.864\...

Iпытался использовать grep -Pzo, но я понятия не имею, как его использовать.

Как уже упоминалось, одно значение можно разбить на две строки:

...-90.80
234,...

И его следует считатьтакое же количество.Иногда только знак минус находится в верхней строке, а остальные цифры в следующей строке:

...,-
56.656,...

Пример вывода из Gaussian :

 433513773\H,-0.5821679865,0.6475216708,0.9536248473\H,-0.7834605038,0.
 4523031701,2.780055657\\Version=ES64L-G09RevD.01\HF=-156.0385049,-156.
 312885,-156.0311709,-156.0310505,-156.0309275,-156.0308023,-156.030548
 ,-156.0304151,-156.0302832,-156.0301504,-156.0300168,-15,8492,84298484
 .0385128\RMSD=4.113e-09,3.064e-09,3.538e-09,3.945e-09,9.452e-09,9.542e
 -09,9.805e-09,9.877e-09,9.916e-09,2.730e-09,3.175e-09,3.077e-09,3.301e

Пример того, какой должен быть файл, который мне нужен

-156.0385049
-156.312885
-156.0311709
-156.0310505
-156.0309275
-156.0308023
-156.030548
-156.0304151
-156.0302832
-156.0301504
-156.0300168
-156.84928429

Ответы [ 3 ]

3 голосов
/ 29 апреля 2019

С любым awk в любой оболочке на любой коробке UNIX:

$ awk -v RS='\\' -F, -v OFS='\n' 'sub(/^HF=/,""){gsub(/[[:space:]]+/,""); $1=$1; print}' file
-156.0385049
-156.312885
-156.0311709
-156.0310505
-156.0309275
-156.0308023
-156.030548
-156.0304151
-156.0302832
-156.0301504
-156.0300168
-15
8492
84298484.0385128

Похоже, что последнее поле в вашем примере ввода не соответствует ожидаемому. Если ваш awk не поддерживает классы символов POSIX, например nawk, затем просто измените [[:space:]] на [ \t\n].

0 голосов
/ 28 апреля 2019

sed решение:

sed -En '/\HF/{
s/^.*\HF=//;
:label1
N;
/\\/!{b label1}
N;
s/[[:space:]]+//g;
s/,/\n/g;s/\\.*//gp;
q;
}' file > outfile

Вывод

-156.0385049
-156.312885
-156.0311709
-156.0310505
-156.0309275
-156.0308023
-156.030548
-156.0304151
-156.0302832
-156.0301504
-156.0300168
-15
8492
84298484.0385128

Сожаление : здесь жестко запрограммирован перевод новой строки :(

0 голосов
/ 28 апреля 2019

Как то так?

awk -F '\' '!p && $2 ~ /^HF=/ { $1=""; p=$0; next }
    p && NF>1 { p = p $1; print p; p="" }
    p { p = p $0 }' file >newfile

Если мы увидим HF=, начните собирать вещи в p. Если p установлено, мы собираем; продолжайте собирать, пока мы не увидим еще одну обратную косую черту. Когда мы увидим его, напечатайте собранный p и начните все заново с пустого p (т.е. мы больше не собираем данные для вывода, пока не увидим следующий маркер запуска снова).

Обратите внимание, что это предполагает, что в строке не может быть более одной обратной косой черты. Если вам нужно это поддержать, потребуется немного более сложный скрипт. (В частности, вы не можете доверять $2, чтобы он содержал `HF =, но вам нужно было бы перебрать все поля и проверить, какое из них является фактическим началом.)

grep не подходит для этого, и сам Bash также не особенно хорошо оснащен. Вы можете попробовать sed, но это больше язык только для записи, поэтому он редко рекомендуется для нетривиальных задач.

...