Как использовать сортировку по команде 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 для сортировки ТОЛЬКО игроков и их чисел?

KM142646
источник
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
Wayne_Yux
источник
К сожалению, я использую скрипт, и команда 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
steeldriver
источник
5

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

... | sort -k2,2

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

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

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

heemayl
источник
Пожалуйста, проверьте комментарий на сообщение Уэйна для того, что мне нужно
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
RedGrittyBrick
источник
Зачем определять функцию?
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"}
DMBailey
источник