awk liner для форматирования входных данных в желаемый результат

К сожалению, msmtp не помогает вам с полем Кому :, отображаемым почтовыми клиентами. Он использует только адреса, которые вы предоставляете для связи с почтовым сервером --по какой-либо причине, он ничего не делает для включения этих адресов в тело сообщения.

This behavior is different from its handling of the From: and Date: fields, which will be automatically included by default (read more).

Вы можете увидеть это непосредственно, запустив в подробном режиме (поиск строк после " --> 354 Go ahead..."):

  • сравнитьecho "Subject: Test\r\n\r\nMessage contents\r\n" | msmtp -v email@example.com
  • противecho "To: email@example.com\r\nSubject: Test\r\n\r\nMessage contents\r\n" | msmtp -v email@example.com

Как правило, почтовые серверы с радостью принимают такие сообщения --, и многие также с радостью их доставляют --, но некоторые компании с несложными технологиями ошибочно помечают все такие сообщения как спам. В этой ситуации единственным выходом может быть включение поля To:в сообщение, переданное по каналу msmtp . (Возможно, даже не обязательно указывать действующий адрес электронной почты Кому :.)

-1
18.08.2020, 11:47
2 ответа

С помощью GNU awk для FPATи FIELDWIDTHS(, а затем с использованием сокращения gawks \s/\Sдля[[:space:]]/[^[:space:]]):

$ cat tst.awk
BEGIN { OFS="\t" }

/^\s*$/ { next }        # skip blank lines

/^\s*QSUM\s/ {          # start of a new record
    numRecs++
    lineNr = 0
}

{
    if ( (++lineNr) % 2 == 1 ) {
        # tags line so find every tag and field width
        FPAT = "\\S+\\s*"
        $0 = $0
        for (i=1; i<=NF; i++) {
            tag = $i
            fw = (i>1 ? fw " " : "") (i<NF ? length(tag) : "*")
            gsub(/^\s+|\s+$/,"",tag)
            if ( !(tag in tagNames2nrs) ) {
                tagNrs2names[++numTags] = tag
                tagNames2nrs[tag] = numTags
            }
            fldNr2tagNr[i] = tagNames2nrs[tag]
        }
        FPAT = ""
    }
    else {
        # vals line so use the field widths found for tags
        FIELDWIDTHS = fw
        $0 = $0
        for (i=1; i<=NF; i++) {
            val = $i
            gsub(/^\s+|\s+$/,"",val)
            tagNr = fldNr2tagNr[i]
            vals[numRecs,tagNr] = val
        }
        FIELDWIDTHS = ""
    }
}

END {
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tagNrs2names[tagNr]
        printf "%s%s", tag, (tagNr<numTags ? OFS : ORS)
    }

    for (recNr=1; recNr<=numRecs; recNr++) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            val = vals[recNr,tagNr]
            printf "%s%s", val, (tagNr<numTags ? OFS : ORS)
        }
    }
}

.

$ awk -f tst.awk file | column -s$'\t' -t
QSUM  HEADER                        STOCK  DATE    TIME       TI  JPS  TNN  LTNN  PP   JP  AA  NS            CPOODE  TYPE  AI  PNC   FLAG    CPO
206   CC-USER REJECT SENT           TNPPP  200322  104914600           8    6     0    1   4   899599991119          12    18
206   CC-USER REJECT SENT           TNPPP  200322  115844000           8    6     0    1   4   899599991555          12    18
103   SUITE FAIL, SUBTRACT FAILURE  TPNRM  200318  031124100  2        177        123  1   4   999999999999                    1499  ORIGIN
103   SUITE FAIL, SUBTRACT FAILURE  TPNRM  200318  031124200  2        177        123  1   4   999999999999                    1499  ORIGIN

Поскольку каждая пара строк имеет разные поля, некоторые из которых пусты, мы должны полагаться на фиксированные с полями для чтения данных, но мы не знаем, сколько полей и какой они ширины, пока не попытаемся их прочитать. Итак, этот скрипт использует FPAT для поиска каждого тега (, также известного как имя, или заголовок, или название ), в каждой строке тегов :

.
TI         JPS        TNN        LTNN       PP         JP

для определения ширины каждого поля (включает имя тега и последующие пробелы ), а затем может использовать FIELDWIDTHS для считывания значений из строки последующих значений:

                      8          6          0          1

как поля фиксированной ширины, даже если какое-либо из полей пусто.

Я не собираюсь комментировать это или иным образом объяснять это более подробно, поскольку ИМХО код довольно ясен, вы задаете МНОГО вопросов по манипулированию текстом, поэтому пришло время немного узнать об awk, прочитав код., поиск справочной страницы, добавление операторов print, где вам нужно увидеть, какие значения имеют переменные, и т. д. Если после всего этого у вас есть конкретные вопросы, то, конечно, не стесняйтесь спрашивать.

Вышеприведенное было выполнено для этого входного файла, который совпадает с файлом в вашем вопросе, но с непоследовательными проблемами выравнивания с QSUM, STOCK, DATA,и заголовки TIME исправлены, потому что я не верю, что ваш реальный ввод может быть таким беспорядочным (, но если это так, это будет легко настроить, чтобы справиться с этим):

$ cat file

QSUM HEADER                          STOCK   DATE    TIME
206  CC-USER REJECT SENT             TNPPP   200322  104914600

TI         JPS        TNN        LTNN       PP         JP
                      8          6          0          1

AA         NS                                          CPOODE
4          899599991119

TYPE       AI
12         18

QSUM HEADER                          STOCK   DATE    TIME
206  CC-USER REJECT SENT             TNPPP   200322  115844000

TI         JPS        TNN        LTNN       PP         JP
                      8          6          0          1

AA         NS                                          CPOODE
4          899599991555

TYPE       AI
12         18
QSUM HEADER                         STOCK   DATE    TIME
103  SUITE FAIL, SUBTRACT FAILURE   TPNRM   200318  031124100

TI         PNC        TNN        PP         JP         AA
2          1499       177        123        1          4

NS                                          FLAG
999999999999                                ORIGIN

TI         CPO


QSUM HEADER                         STOCK   DATE    TIME
103  SUITE FAIL, SUBTRACT FAILURE   TPNRM   200318  031124200

TI         PNC        TNN        PP         JP         AA
2          1499       177        123        1          4

NS                                          FLAG
999999999999                                ORIGIN

TI         CPO
3
18.03.2021, 23:11

Я бы перевернул эту проблему с ног на голову. Начните с раздела BEGIN, создав массив из столбцов массива, который вы хотите использовать в качестве вывода , по порядку. Ширина столбца и текст (, чтобы начать с):

BEGIN {
    defCol[ 1] = "  5 QSUM";
    defCol[ 2] = " 28 HEADER";
   ...
    defCol[19] = "  6 CPO";
}

Подтвердите это, написав функцию, которая просто печатает заголовок. Вы можете выполнить итерацию через defCol, например:

printf ("%.*s", 0 + defCol[j], substr (defCol[j], 5);

Затем напишите функцию, которая собирает массив входных строк между одним вводом QSUM и следующим, пропуская пустые строки. Строки только с прописными буквами и пробелами — это заголовки, строки с чем-либо еще — это данные с полями, выровненными до предыдущей строки заголовка. (Я предполагаю, что смещение верхней строки как при вводе, так и при выводе является опечаткой ).

Для каждой группы вы сопоставляете заголовок с именем столбца, чтобы определить, к какой голубиной -норе принадлежит элемент данных (в виде массива, индексируемого так же, как defCol, естественно ). Затем вы можете распечатать строку сведений, используя индексы defCol для упорядочивания полей и ширину defCol в средстве форматирования printf.

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

Более подробное функциональное описание:

Во-первых, вам нужно условие, которое определяет, когда вы завершили одну группу ввода --, которая раньше была «перерывом управления». Это могло произойти в строке, содержащей «QSUM HEADER» или что-то подобное, с некоторым шаблоном, позволяющим изменять интервалы. Вы также не хотите, чтобы это произошло в первый раз (, потому что у вас еще не было группы ), и вам нужно, чтобы это также произошло в состоянии END (, потому что у последней группы не будет заголовок, чтобы активировать его ).

Остальную часть ввода можно использовать для добавления всех частей заголовка в одну длинную строку и всех частей данных в другую длинную строку.и игнорировать все пустые строки.

Чтобы вывести группу, вы просматриваете строку заголовка, ища позиции заголовков данных, и выбираете поля в соответствующих местах в строке данных, используя функции match ()и substr (). Вы сохраняете каждый элемент данных в массиве, используя те же индексы, что и элементы заголовка.

Затем вы можете вывести поля данных точно так же, как вы делали фиксированные тексты заголовков.

Все это звучит сбивающе с толку, но все достаточно прямолинейно -. Я не могу написать код прямо сейчас, но я, вероятно, смогу опубликовать структуру позже сегодня.

На самом деле, ввод (в том виде, в котором он опубликован ), вероятно, не поддается синтаксическому анализу с какой-либо надежностью из-за изменчивости интервалов.

Например, значения в разделе ЗАПАС, ДАТА и ВРЕМЯ не всегда совпадают со значениями. Мы не можем просто считать поля, потому что в HEADER есть пробелы. Мы либо возвращаемся к двум или более пробелам в качестве разделителя, либо к некоторому «достаточно близкому» выравниванию полей. И это только пример из 40 -строк, :другие опасности ждут впереди.

1
18.03.2021, 23:11

Теги

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