Як використовувати сортування в команді 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 та оболонки у своєму запитанні. Здається, ви хочете зробити сортування за вашим скриптом awk , а не в скрипті оболонки, який викликає його. Якщо це правильно, то будь ласка, відредагуйте своє запитання та замініть два випадки "shell" на "awk". Окреме зауваження: так, у awk є функція сортування, але вона дуже задіяна: ви повинні зберігати всі рядки в масиві, введеному в їх друге поле, з якого вам потрібно буде витягнути x, а потім встановити PROCINFO["sorted_in"]криптовалютне значення, потім вивести масив. Я б не поїхав туди.
zwets

1
Я маю на увазі: я б не поїхав туди, враховуючи простоту ... | sort -k2,2.
zwets

@zwets Як я можу реалізувати, ...| sort -k2,2якщо є інші рядки, які потрібно надрукувати? Перевірте відредаговане запитання.
141464 KM

За 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

На жаль, я використовую сценарій, і команда сортування буде змішана з багатьма іншими результатами. Чи є спосіб сортування результатів {print x, $2}безпосередньо в коді сценарію? Я отримую помилку при трубопроводі if(sum[x] > 500) {print x, $2} | sort -k2.
142 KM KM 1616

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 Будь ласка, перевірте правки, внесені до оригінального запитання.
142 KM KM 1616

Тоді вам, мабуть, потрібна відповідь від @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.


Будь ласка, ознайомтесь із коментарем до публікації Wayne, що мені потрібно
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

Щоб сортувати ваші дані для друку:

  • Припустимо, ви хочете надрукувати друге поле (пробіл розділений), використовуйте це:

    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.