Как использовать awk для извлечения поля в кавычках?

я использую

awk '{ printf "%s", $3 }'

для извлечения некоторого поля из строки, разделенной пробелом. Конечно, я получаю частичные результаты, когда поле заключено в кавычки со свободными пробелами внутри. Может ли кто-нибудь предложить решение, пожалуйста?


person mmonem    schedule 11.08.2010    source источник
comment
покажите формат входного файла... и желаемый результат!   -  person ghostdog74    schedule 11.08.2010


Ответы (4)


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

{
    s = $0
    i = 0
    split("", a)
    while ((m = match(s, /"[^"]*"/)) > 0) {
        # Add all unquoted fields before this field
        n = split(substr(s, 1, m - 1), t)
        for (j = 1; j <= n; j++)
            a[++i] = t[j]
        # Add this quoted field
        a[++i] = substr(s, RSTART + 1, RLENGTH - 2)
        s = substr(s, RSTART + RLENGTH)
        if (i >= 3) # We can stop once we have field 3
            break
    }
    # Process the remaining unquoted fields after the last quoted field
    n = split(s, t)
    for (j = 1; j <= n; j++)
        a[++i] = t[j]
    print a[3]
}
person schot    schedule 11.08.2010
comment
Это достаточно сложное решение. Если нет простого одного решения, я бы выбрал perl - person mmonem; 11.08.2010

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

$ cat file
field1 field2 "field 3" field4 "field5"

$ awk -F'"' '{for(i=2;i<=NF;i+=2) print $i}' file
field 3
field5
person ghostdog74    schedule 11.08.2010
comment
На самом деле это журнал веб-сервера Apache. Кажется, что awk не может сделать это легко. - person mmonem; 11.08.2010
comment
@mmonem Тогда это может быть полезно: serverfault.com/questions/11028/ - person schot; 12.08.2010

Вот возможное альтернативное решение этой проблемы. Он работает, находя поля, которые начинаются или заканчиваются кавычками, а затем объединяя их вместе. В конце он обновляет поля и NF, поэтому, если вы поместите больше шаблонов после того, который выполняет слияние, вы можете обрабатывать (новые) поля, используя все обычные функции awk.

Я думаю, что это использует только функции POSIX awk и не полагается на расширения gawk, но я не совсем уверен.

# This function joins the fields $start to $stop together with FS, shifting
# subsequent fields down and updating NF.
#
function merge_fields(start, stop) {
    #printf "Merge fields $%d to $%d\n", start, stop;
    if (start >= stop)
        return;
    merged = "";
    for (i = start; i <= stop; i++) {
        if (merged)
            merged = merged OFS $i;
        else
            merged = $i;
    }
    $start = merged;

    offs = stop - start;
    for (i = start + 1; i <= NF; i++) {
        #printf "$%d = $%d\n", i, i+offs;
        $i = $(i + offs);
    }
    NF -= offs;
}

# Merge quoted fields together.
{
    start = stop = 0;
    for (i = 1; i <= NF; i++) {
        if (match($i, /^"/))
            start = i;
        if (match($i, /"$/))
            stop = i;
        if (start && stop && stop > start) {
            merge_fields(start, stop);
            # Start again from the beginning.
            i = 0;
            start = stop = 0;
        }
    }
}

# This rule executes after the one above. It sees the fields after merging.
{
    for (i = 1; i <= NF; i++) {
        printf "Field %d: >>>%s<<<\n", i, $i;
    }
}

Во входном файле, например:

thing "more things" "thing" "more things and stuff"

он производит:

Field 1: >>>thing<<<
Field 2: >>>"more things"<<<
Field 3: >>>"thing"<<<
Field 4: >>>"more things and stuff"<<<
person benj    schedule 01.09.2014

Если вы просто ищете конкретное поле, то

$ cat file
field1 field2 "field 3" field4 "field5"

awk -F"\"" '{print $2}' file

работает. Он разбивает файл на «, поэтому второе поле в приведенном выше примере — это то, что вам нужно.

person Alan Swindells    schedule 14.06.2015