Как использовать сортировку по команде awk print?


8

У меня есть пара команд в сценарии awk, который я пишу:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2}

Какие выводы:

Here are some players and their numbers, sorted by last name
Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55

Как я могу использовать sortкоманду в своем скрипте awk для сортировки ТОЛЬКО игроков и их чисел?


3
Учитывая ваши комментарии к ответам, вы, кажется, сбиваете с толку сценарий awk и shell в своем вопросе. Похоже, вы хотите выполнить сортировку в своем скрипте awk , а не в скрипте оболочки, вызывающем его. Если это так, отредактируйте ваш вопрос и замените два вхождения 'shell' на 'awk'. Отдельное примечание: да, в awk есть средство сортировки, но оно довольно сложное: вы должны сохранить все строки в массиве, ключом которого является их второе поле, из которого вам нужно извлечь x, затем установить PROCINFO["sorted_in"]загадочное значение, затем выведите массив. Я бы не пошел туда.
— zwets

1
Я имею в виду: я бы не пошел туда, учитывая простоту ... | sort -k2,2.
— zwets

@zwets Как бы я реализовал, ...| sort -k2,2если есть другие строки, которые должны быть напечатаны? Проверьте отредактированный вопрос.
— KM142646

Используя echoстроку заголовка оболочки, затем запустите awk | sortконвейер.
— Zwets

Ответы:


12

Вы можете добавить | sort -k2к своей команде. Это будет сортировать в алфавитном порядке на основе второго столбца.

Пример:

$ echo "Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55" | sort -k2

результаты в

Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

К сожалению, я использую скрипт, и команда sort будет смешана со многими другими выходными данными. Есть ли способ отсортировать вывод {print x, $2}непосредственно в коде скрипта? Я получаю сообщение об ошибке при конвейере if(sum[x] > 500) {print x, $2} | sort -k2.
— KM142646

3
@KMoy: if(sum[x] > 500) {print x, $2}код Awk, а | sort -k2команда оболочки. Очевидно, что вы не можете смешивать эти два, потому что это разные языки. Вместо этого вам нужно применить sortкоманду к выводу интерпретатора Awk, который выполняет ваш фрагмент кода Awk. Если вы не знаете, что я имею в виду, пожалуйста, расширьте свой вопрос, чтобы дать нам полную картину.
— Дэвид Фёрстер

1
Вы пишете сценарий оболочки, верно? Тогда у вас есть два варианта: 1. запустить ./my-script.sh | sort -k2. 2. добавить `| Сортируйте -k2` в строке вашего скрипта, которая выдает результат, указанный в вашем вопросе.
— Wayne_Yux

@Wayne_Yux Пожалуйста, проверьте изменения, внесенные в оригинальный вопрос.
— KM142646

Тогда вам, вероятно, нужен ответ от @steeldriver
— Wayne_Yux

9

Хотя я бы не рекомендовал это (учитывая относительную простоту передачи результата через внешнюю sortкоманду), вы можете сделать это по крайней мере с последними версиями GNU awk (по крайней мере, 4.0 IIRC), как описано в Сортировке значений и индексов массива с gawk

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

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

Теперь вы можете использовать PROCINFO["sorted_in"]метод сортировки массива, упомянутый в комментариях @zwets

PROCINFO["sorted_in"] = "mycmp";
for(i in a) print i, a[i];

Положить его вместе

#!/usr/bin/gawk -f

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

{
  a[$1" "$2] = $3;
}

END {
  PROCINFO["sorted_in"] = "mycmp";
  for(i in a) print i, a[i];
}

Тестирование:

$ ./namesort.awk yourfile
Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

В более ранних или более старых версиях awk лучше всего хранить индексированные данные Lastname Firstnameвместо этого, сортировать с обычными asorti, а затем разбивать и менять поля индексов при прохождении массива для его печати:

awk '
  {a[$2" "$1]=$3} 
  END {
    n=asorti(a,b); for (i=1;i<=n;i++) {split(b[i],s); print s[2], s[1], a[b[i]]}
}' yourfile

5

Чтобы sortтолько через пробел отделить второе поле, используйте ключ -k2,2:

... | sort -k2,2

по умолчанию sortсортировка выполняется лексикографически.

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

Также проверьте man sort.


Пожалуйста, проверьте комментарий на сообщение Уэйна для того, что мне нужно
— KM142646

1

Пытаться

awk -f myscript.awk | sort -k2

Где myscript.awk содержит чисто команды awk.

Если ваш настоящий сценарий является сценарием оболочки, у вас есть несколько вариантов, включая

  • Труба выводится через сортировку. ./myscript.bash | sort -k2
  • Переписать код как функцию внутри скрипта
    вместо

    $ cat t1
    #!/bin/bash
    for i in 2 4 3 1 5;
    do
      echo $i
    done
    
    $ ./t1
    2
    4
    3
    1
    5
    

    Делать

    $ cat t2
    #!/bin/bash
    function foo {
      for i in 2 4 3 1 5;
      do
        echo $i
      done
    }
    foo | sort
    
    $ ./t2
    1
    2
    3
    4
    5
    

Но обратите внимание, что вы можете также применить сортировку к структуре do ... done вместо создания функции.

    do
       echo $i
    done | sort

Зачем определять функцию?
— Zwets

@zwets, это упрощает передачу результатов произвольного кода, включая циклические управляющие структуры, по конвейеру. Есть случаи, когда это не нужно, но я считаю это полезным общим шаблоном. Я отредактирую свой ответ, чтобы продемонстрировать это.
— RedGrittyBrick

1

Чтобы отсортировать данные для печати:

  • Предположим, что вы хотите напечатать 2-е поле (через пробел), используйте это:

    awk '{print $2}' data.txt | sort
    

    например:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Если вы хотите распечатать все свои, data.txtно отсортированные по столбцу 2, то:

    $awk '{print}'|sort -k2
    2 Amit 30
    1 Kedar 20
    3 Rahul 21
    

Используйте эту логику в ваших требованиях.

Вы можете использовать man sortдля более интересных функций sort.


0

как насчет ниже:

 awk 'BEGIN{str="1\n2\n3\n4"; system("echo -e \""str"\" | sort -r")}'

это работает, когда я проверил.


0
print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2"}

Чтобы отсортировать вывод в файл:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.