Итерация по разделенной строке по другой строке - PullRequest
0 голосов
/ 03 октября 2019

Я хочу создать скрипт bash для анализа данных, возвращаемых этой командой:

openvpn --show-pkcs11-ids /usr/lib/libeTPkcs11.so

Типичный вывод:

The following objects are available for use.
Each object shown below may be used as parameter to
--pkcs11-id option please remember to use single quote mark.

Certificate
       DN:             XXX
       Serial:         XXXX
       Serialized id:  XXXX

Certificate
       DN:             XXXX
       Serial:         XXXX
       Serialized id:  XXXX

Certificate
       DN:             XXXXX
       Serial:         XXXX
       Serialized id:  XXXX

Я хочу получить массив в bashсодержит 3 элемента: 3 блока «Сертификат». Я перепробовал много методов разделения, но все они выводят только команду echo, а не фактический массив.

Есть идеи?

Thx!

Ответы [ 2 ]

2 голосов
/ 03 октября 2019

В этом случае было бы намного проще и (намного быстрее) использовать awk. awk предоставляет массивы и гораздо более способен обрабатывать входные записи, чем read. С awk вы просто пишете правила, которые будут применяться к каждой строке ввода. В вашем случае вам просто нужно определить, начинается ли строка с "DN:", "Serial:" или "Serialized". Затем вы можете сохранить связанное значение в отдельном массиве, скажем, массивах dn, serial и serid. Чтобы выполнить это в awk, вам ничего не нужно:

awk '
    $1 == "Certificate" {n++};              # increment n
    NF == 2 {                               # fill dn & serial array
        $1 == "DN:" && dn[n]=$2
        $1 == "Serial:" && serial[n]=$2
    }
    NF == 3 {                               # fill serid array
        $1 == "Serialized" && serid[n]=$3
    }
END {   # output results
    print "\nDN:\t\tSerial:\t\tSerialized id:"
    for (i in dn) print dn[i], "\t\t", serial[i], "\t\t", serid[i]
}' file

Выше, если первое поле ($1) равно "Certificate", вы просто увеличиваете счетчик. Если в строке 2 поля (NF == 2), то вы проверяете, начинается ли строка с "DN:" или "Serial" и добавляете 2-е поле в соответствующий массив. Если в строке 3 поля ("Serialized", "id:" и ваше значение), вы сохраняете значение в массиве serid.

Со всеми сохраненными значениями вы можете перебирать массивы в правиле END,предоставляя любой вывод, который вам нужен. Над ним просто выводится контент в табличной форме. Вы можете просто скопировать / усечь вставку средней кнопкой мыши в командной строке для проверки.

Пример Использование / Вывод

$ awk '
>     $1 == "Certificate" {n++};              # increment n
>     NF == 2 {                               # fill dn & serial array
>         $1 == "DN:" && dn[n]=$2
>         $1 == "Serial:" && serial[n]=$2
>     }
>     NF == 3 {                               # fill serid array
>         $1 == "Serialized" && serid[n]=$3
>     }
> END {   # output results
>     print "\nDN:\t\tSerial:\t\tSerialized id:"
>     for (i in dn) print dn[i], "\t\t", serial[i], "\t\t", serid[i]
> }' file

DN:             Serial:         Serialized id:
XXX              XXXX            XXXX
XXXX             XXXX            XXXX
XXXXX            XXXX            XXXX

Для обработки больших файлов, awkбудет на порядка быстрее, чем цикл в сценарии оболочки. Дайте мне знать, удовлетворяет ли это вашим потребностям, если вам нужна дополнительная помощь.

Редактировать за комментарий

Если вы имеете дело с файлом, в котором есть смешанные табуляции и пробелыПри использовании разделителей это может вызвать проблемы при разборе awk с использованием стандартного разделителя полей (пробел). Чтобы рассматривать последовательность смешанных пробелов / табуляций как разделитель, в GNU awk вы можете указать регулярное выражение для разделителя. Например, учитывая последовательность из одного или нескольких пробелов или табуляций, можно указать как -F'[ \t]+'. В приведенном ниже примере используется разделитель. (примечание: в результате номера полей изменятся)

awk -F'[ \t]+' '
    $1 == "Certificate" {n++};              # increment n
    NF == 3 {                               # fill dn & serial array
        $2 == "DN:" && dn[n]=$3
        $2 == "Serial:" && serial[n]=$3
    }
    NF == 4 {                               # fill serid array
        $2 == "Serialized" && serid[n]=$4
    }
END {   # output results
    print "\nDN:\t\tSerial:\t\tSerialized id:"
    for (i in dn) print dn[i], "\t\t", serial[i], "\t\t", serid[i]
}' f

Пример использования / Вывод

С такими же данными вы получите:

$ awk -F'[ \t]+' '
>     $1 == "Certificate" {n++};              # increment n
>     NF == 3 {                               # fill dn & serial array
>         $2 == "DN:" && dn[n]=$3
>         $2 == "Serial:" && serial[n]=$3
>     }
>     NF == 4 {                               # fill serid array
>         $2 == "Serialized" && serid[n]=$4
>     }
> END {   # output results
>     print "\nDN:\t\tSerial:\t\tSerialized id:"
>     for (i in dn) print dn[i], "\t\t", serial[i], "\t\t", serid[i]
> }' f

DN:             Serial:         Serialized id:
XXX              XXXX            XXXX
XXXX             XXXX            XXXX
XXXXX            XXXX            XXXX

Не зная, какова структура пробела / табуляции вашего опубликованного текста, это должно учитывать любой случай.

Дальнейшее обновление Публикация входных данных, взятых из вопроса

Ниже приведен входной файл f (или file), используемый с примерами выше. Это было взято из вашего вопроса, но нет никакой гарантии, что перевод пробела / табуляции будет таким же, как в вопросе. Последний пример выше должен справиться с этим независимо. Единственное другое предостережение: если у вас есть файл с окончанием строки DOS, который вы вводите в awk - он не будет работать. Вы можете проверить, запустив утилиту file yourfilename, и она сообщит, что в DOS CRLF имеются окончания строки. Затем вы можете использовать dos2unix yourfilename, чтобы исправить проблему и преобразовать файл в окончания строк Unix / POSIX.

Пример входного файла

$ cat f
The following objects are available for use.
Each object shown below may be used as parameter to
--pkcs11-id option please remember to use single quote mark.

Certificate
       DN:             XXX
       Serial:         XXXX
       Serialized id:  XXXX

Certificate
       DN:             XXXX
       Serial:         XXXX
       Serialized id:  XXXX

Certificate
       DN:             XXXXX
       Serial:         XXXX
       Serialized id:  XXXX

Hexdump

$ hexdump -Cv f
00000000  54 68 65 20 66 6f 6c 6c  6f 77 69 6e 67 20 6f 62  |The following ob|
00000010  6a 65 63 74 73 20 61 72  65 20 61 76 61 69 6c 61  |jects are availa|
00000020  62 6c 65 20 66 6f 72 20  75 73 65 2e 0a 45 61 63  |ble for use..Eac|
00000030  68 20 6f 62 6a 65 63 74  20 73 68 6f 77 6e 20 62  |h object shown b|
00000040  65 6c 6f 77 20 6d 61 79  20 62 65 20 75 73 65 64  |elow may be used|
00000050  20 61 73 20 70 61 72 61  6d 65 74 65 72 20 74 6f  | as parameter to|
00000060  0a 2d 2d 70 6b 63 73 31  31 2d 69 64 20 6f 70 74  |.--pkcs11-id opt|
00000070  69 6f 6e 20 70 6c 65 61  73 65 20 72 65 6d 65 6d  |ion please remem|
00000080  62 65 72 20 74 6f 20 75  73 65 20 73 69 6e 67 6c  |ber to use singl|
00000090  65 20 71 75 6f 74 65 20  6d 61 72 6b 2e 0a 0a 43  |e quote mark...C|
000000a0  65 72 74 69 66 69 63 61  74 65 0a 20 20 20 20 20  |ertificate.     |
000000b0  20 20 44 4e 3a 20 20 20  20 20 20 20 20 20 20 20  |  DN:           |
000000c0  20 20 58 58 58 0a 20 20  20 20 20 20 20 53 65 72  |  XXX.       Ser|
000000d0  69 61 6c 3a 20 20 20 20  20 20 20 20 20 58 58 58  |ial:         XXX|
000000e0  58 0a 20 20 20 20 20 20  20 53 65 72 69 61 6c 69  |X.       Seriali|
000000f0  7a 65 64 20 69 64 3a 20  20 58 58 58 58 0a 0a 43  |zed id:  XXXX..C|
00000100  65 72 74 69 66 69 63 61  74 65 0a 20 20 20 20 20  |ertificate.     |
00000110  20 20 44 4e 3a 20 20 20  20 20 20 20 20 20 20 20  |  DN:           |
00000120  20 20 58 58 58 58 0a 20  20 20 20 20 20 20 53 65  |  XXXX.       Se|
00000130  72 69 61 6c 3a 20 20 20  20 20 20 20 20 20 58 58  |rial:         XX|
00000140  58 58 0a 20 20 20 20 20  20 20 53 65 72 69 61 6c  |XX.       Serial|
00000150  69 7a 65 64 20 69 64 3a  20 20 58 58 58 58 0a 0a  |ized id:  XXXX..|
00000160  43 65 72 74 69 66 69 63  61 74 65 0a 20 20 20 20  |Certificate.    |
00000170  20 20 20 44 4e 3a 20 20  20 20 20 20 20 20 20 20  |   DN:          |
00000180  20 20 20 58 58 58 58 58  0a 20 20 20 20 20 20 20  |   XXXXX.       |
00000190  53 65 72 69 61 6c 3a 20  20 20 20 20 20 20 20 20  |Serial:         |
000001a0  58 58 58 58 0a 20 20 20  20 20 20 20 53 65 72 69  |XXXX.       Seri|
000001b0  61 6c 69 7a 65 64 20 69  64 3a 20 20 58 58 58 58  |alized id:  XXXX|
000001c0  0a                                                |.|
000001c1

Дайте мне знать результаты вашего рассмотрения файла.

1 голос
/ 03 октября 2019

Вы можете использовать AWK для этого. Это инструмент, специально созданный для преобразования табличного вывода.

openvpn --show-pkcs11-ids /usr/lib/libeTPkcs11.so | grep 'Certificate\|DN:\|Serial:\|Serialized id:' | awk -v RS="Certificate" '{print $2,$4,$7}'

Объяснение:

grep 'Сертификат \ | DN: \ | Serial: \ | Serialized id:'- Выберите только интересные строки вывода
awk -v RS = "Сертификат" '{print $ 2, $ 4, $ 7}' - См. Ниже комментарий

Комментарий : AWKпозволяет изменить разделитель записей с помощью параметра -v RS =. По умолчанию это новая строка, поэтому каждая строка файла является записью, но ее можно изменить на любую строку, например «Сертификат».

Вывод не является массивом, но каждый сертификат описан отдельной строкой, которую вы можете далее направить другому инструменту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...