Как выполнить сортировку в сценарии awk в Linux?

В Linux и с оболочками, которые реализуют здесь -документы с доступными для записи временными файлами (, например, zshили bashверсии до 5.1 ), вы можете сделать:

{
  out=$(
    chmod u+w /dev/fd/3 && # needed for bash5.0
      ls /dev/null /x 2> /dev/fd/3
  )
  status=$?
  err=$(cat<&3)
} 3<\n' out "$out" err "$err" status "$status"

(где ls /dev/null /x— это пример команды, которая выводит что-то как на стандартный вывод, так и на стандартный вывод ).

С помощью zshвы также можете:

(){ out=$(ls /dev/null /x 2> $1) status=$? err=$(<$1);} =(:)

(где =(cmd)— форма подстановки процессов, использующая временные файлы, и (){ code; } argsанонимные функции ).

В любом случае лучше использовать временные файлы. Любое решение, использующее конвейеры, будет подвержено взаимоблокировкам в случае больших выходных данных. Вы можете читать stdout и stderr через два отдельных канала и использовать select()/poll()и некоторые чтения в цикле для чтения данных по мере их поступления из двух каналов, не вызывая блокировки -, но это было бы довольно сложно и Насколько мне известно, только zshимеет select()встроенную поддержку -и только yashнеобработанный интерфейс к pipe()(, подробнее об этом в Чтение/запись в тот же файловый дескриптор с перенаправлением оболочки).

Другим подходом может быть сохранение одного из потоков во временной памяти вместо временного файла.Аналогично синтаксису(zshили bash):

{
  IFS= read -rd '' err
  IFS= read -rd '' out
  IFS= read -rd '' status
} < <({ out=$(ls /dev/null /x); } 2>&1; printf '\0%s' "$out" "$?")

(предполагается, что команда не выводит NUL)

Обратите внимание, что $errбудет включать завершающий символ новой строки.

Другие подходы могут заключаться в другом оформлении stdout и stderr и удалении оформления при чтении:

out= err= status=
while IFS= read -r line; do
  case $line in
    (out:*)    out=$out${line#out:}$'\n';;
    (err:*)    err=$err${line#err:}$'\n';;
    (status:*) status=${line#status:};;
  esac
done < <(
  {
    {
      ls /dev/null /x |
        grep --label=out --line-buffered -H '^' >&3
      echo >&3 "status:${PIPESTATUS[0]}" # $pipestatus[1] in zsh
    } 2>&1 |
      grep --label=err --line-buffered -H '^'
  } 3>&1

)

Это предполагает GNU grepи что строки достаточно короткие. Со строками больше, чем PIPEBUF (4K в Linux ), строки вывода двух greps могут быть искажены вместе в кусках.

2
03.01.2020, 20:30
4 ответа

Вы можете передать awk от printдо"sort"(обратите внимание на кавычки):

$ awk '{print "Fruit",NR, $0 | "sort -k 2 -t, -rn"}' fruit 
Fruit 2 Pears, 50
Fruit 4 Strawberries, 36
Fruit 1 Apples, 12
Fruit 3 Cheries, 7
Fruit 5 Oranges, 2

Итак, чтобы написать numbers, вы можете сделать:

awk '{print "Fruit",NR, $0 | "sort -k 2 -t, -rn > numbers"}' fruit 

Обратите внимание, что я немного упростил ваш awk. Здесь нет необходимости использовать printfили явно печатать OFS, так как вы нигде его не меняете. Я также не вижу, что делает ваш for(i=1;i<=NF;i++)j+=$i. У вас уже есть номер с NR, а ваш printfвсе равно не использовал j.

2
28.04.2021, 23:26

HeapSort можно записать на стандартном awk менее чем в 20 строк. Не ослепительно быстро, но достаточно хорошо вписывается в язык.

-1
28.04.2021, 23:26

GNU awk дает вам удобный способ управления обходом массива :см. Управление обходом массива и Управление сканированием

gawk -F', ' '
    {fruit[$1] = $2}
    END {
        OFS = FS

        printf "\nordered by fruit name\n"
        PROCINFO["sorted_in"] = "@ind_str_asc"
        for (f in fruit) print f, fruit[f]

        printf "\nordered by number\n"
        PROCINFO["sorted_in"] = "@val_num_desc"
        for (f in fruit) print f, fruit[f]
    }
' fruit

выходы

ordered by fruit name
Apples, 12
Cheries, 7
Oranges, 2
Pears, 50
Strawberries, 36

ordered by number
Pears, 50
Strawberries, 36
Apples, 12
Cheries, 7
Oranges, 2
6
28.04.2021, 23:26

Должно быть, у меня были серьезные проблемы с nawk SunOS в 2002 году. Я нашел свой тестовый сценарий, содержащий три реализации awk, которые работают в не -GNU awk:

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

(b )qSort :рекурсивная сортировка разделов. Плохая производительность для больших данных и разбивает стек в mawk для> 2000 элементов. Хотя писать весело.

(c )hSort :сортировка -in -алгоритм situ в 15 строк. Эта куча использует алгоритм индексации для поддержки двоичного дерева (, см. Википедию ).

Этот bash-скрипт содержит awk-функции hSort и hUp, реализующие фактическую сортировку. Одна строка действия помещает все входные данные в массив, а блок END вызывает hSort и сообщает о результатах.

Входные данные — это содержимое «man bash», сначала в виде строк, а затем в виде слов. Мы используем wc, чтобы убедиться, что ничего не потерялось, и sort -c, чтобы доказать, что вывод отсортирован. Тайминги включают служебные данные чтения и печати.

Это тестовый снимок:

Paul--)./hSort

Sorted 5251 elements.

real    0m0.120s
user    0m0.116s
sys     0m0.004s
  5251  44463 273728 hSort.raw
sort: hSort.raw:2: disorder: 
  5251  44463 273728 hSort.srt

Sorted 44463 elements.

real    0m1.336s
user    0m1.316s
sys     0m0.008s
 44463  44463 265333 hSort.raw
sort: hSort.raw:3: disorder: Commands
 44463  44463 265333 hSort.srt

Это сценарий. Наслаждаться!

#! /bin/bash

export LC_ALL="C"

#### Heapsort algorithm.

function hSort {    #:: (void) < text

    local AWK='''
#.. Construct the heap, then unfold it.
function hSort (A, Local, n, j, e) {
    for (j in A) ++n;
    for (j = int (n / 2); j > 0; --j) hUp( j, A[j], n, A);
    for (j = n; j > 1; --j) { e = A[j]; A[j] = A[1]; hUp( 1, e, j - 1, A); }
    return (0 + n);
}
#.. Given an empty slot and its contents, pull any bigger elements up the tree.
function hUp (j, e, n, V, Local, k) {
    while ((k = j + j) <= n) {
        if (k + 1 <= n  &&  STX V[k] < STX V[k + 1]) ++k;
        if (STX e >= STX V[k]) break;
        V[j] = V[k]; j = k;
    }
    V[j] = e;
}
{ U[++nU] = $0; }
END {
    sz = hSort( U);
    printf ("\nSorted %s elements.\n", sz) | "cat 1>&2";
    for (k = 1; k in U; ++k) print U[k];
}
'''
    mawk -f <( printf '%s\n' "${AWK}" )
}

#### Test Package Starts Here.

function Test {
    time hSort < hSort.raw > hSort.srt
    for fn in hSort.{raw,srt}; do wc "${fn}"; LC_ALL="C" sort -c "${fn}"; done
}
    AWK_LINE='{ sub (/^[ \011]+/, ""); print; }'
    AWK_WORD='{ for (f = 1; f <= NF; ++f) print $(f); }'

    #xxx : > hSort.raw; Test        #.. Edge cases.
    #xxx echo "Hello" > hSort.raw; Test
    #xxx { echo "World"; echo "Hello"; } > hSort.raw; Test

    man bash | col -b | mawk "${AWK_LINE}" > hSort.raw; Test
    man bash | col -b | mawk "${AWK_WORD}" > hSort.raw; Test
1
28.04.2021, 23:26

Теги

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