Использование sed, awk или tr для разделения каждой строки с использованием двоеточия (:) в качестве разделителя в формат CSV

У меня есть Kali в качестве виртуальной машины VirtualBox, и я установил драйвер AWUS036ACH с

apt install realtek-rtl88xxau-dkms

После этого выполните следующие команды, чтобы активировать режим монитора:

ifconfig wlan0 down 
iwconfig wlan0 mode monitor
ifconfig wlan0 up
-1
22.04.2020, 05:46
2 ответа

Для полноты картины решение на основе awk-.

Скриптawk-(назовем егоconvert_csv.awk):

#!/bin/awk -f
BEGIN{FS=":";OFS=","}

# Process all non-empty lines
NF>0{
    # Check if the "key" part of the line was not yet encountered, both globally
    # and for the currently processes record.
    # If not encountered globally yet, add to list of headers (=columns).
    new_hdr=1; new_key=1;
    for (i=1; i<=n_hdrs; i++) {if (hdr[i]==$1) new_hdr=0;}
    if (new_hdr) hdr[++n_hdrs]=$1;

    for (key in val) {if (key==$1) new_key=0;}


    # Once no globally new keys are found, consider the "list of headers" as
    # complete and print it as CSV header line.
    if (!new_hdr && !hdr_printed)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", hdr[i], i==n_hdrs?ORS:OFS);
        hdr_printed=1;
    }

    # If the current key was already found in the currently processed record,
    # we assume that a new record was started, and print the data collected
    # so far before collecting data on the next record.
    if (!new_key)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", val[hdr[i]], i==n_hdrs?ORS:OFS);
        delete val;
    }

    # Associate the "value" part of the line with the "key", perform transformations
    # as necessary. Since both the 'gsub()' function used for escaping '"' to '""'
    # and the 'index()' function used to localize ',' return non-zero if an occurence
    # was found, the sum of both return values being > 0 indicates that the field
    # must be quoted.
    quote=gsub("\"","\"\"",$2)+index($2,",");
    if (quote) $2="\""$2"\"";
    val[$1]=$2;
}


# Print the last record. If it was the only record, print the header line, too (this
# is the case if 'new_hdr' is still 'true' at end-of-file).
END {
    if (new_hdr)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", hdr[i], i==n_hdrs?ORS:OFS);
    }

    for (i=1;i<=n_hdrs;i++) printf("%s%s", val[hdr[i]], i==n_hdrs?ORS:OFS);
}

Функция описана в комментариях, но в основном она ищет наборы уникальных ключей и считает запись завершенной, как только ключ, «уже встречавшийся» в строке, найден; затем он печатает запись и очищает временный буфер для сбора следующей записи. Он также применяет преобразования, указанные @mosvy, чтобы соответствовать стандарту CSV для специальных символов в полях.

Назовите это как

awk -f convert_csv.awk input.txt
1
19.03.2021, 02:28

Использование perl, которое присутствует в любом настольном или серверном дистрибутиве Linux:

perl -lne '
   BEGIN{$,=","}
   ($k,$v)=split":",$_,2;
   next unless defined $v;
   for($k,$v){s/"/""/g,$_=qq{"$_"}if/[$,"]/}
   $k=$t{$k}//=$t++;
   if(exists$f[$k]){print@f;@f=()}
   $f[$k]=$v;
   END{print@f;print STDERR sort{$t{$a}<=>$t{$b}}keys%t}
' your_file

Это должно преобразовать файл в стандартный CSV, за исключением того, что заголовок (первая строка с именами полей )будет напечатана в stderr после обработки всего файла. Вы можете сохранить его где-нибудь с помощью ... >body 2>hdr, а затем cat hdr body > final_file.csv.

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

Поля, которые содержат либо ,, либо ", будут помещены внутрь "...", а любое внутреннее "будет экранировано путем дублирования его как""(с использованием соглашения CSV ).

Вы можете настроить разделитель полей, изменив $,=",", например, на.$,="|"(или $,="\t"для вкладок ). Вы можете избавиться от кавычек и экранирования, удалив строку for($k,$v){... }.

Это можно было бы сделать вawk(НЕ в sedили tr, хотя ), только это будет немного сложнее, так как awkне имеет возможности печатать целые массивы сразу (вы должны перебирать их в цикле ), а возможность разбить строку на ограниченное число полей (вам придется использовать substrтрюк для этого ).

2
19.03.2021, 02:28

Теги

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