Bagaimana cara menggunakan sort pada perintah cetak awk?


8

Saya memiliki beberapa perintah dalam skrip awk yang saya tulis:

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

Output yang mana:

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

Bagaimana saya bisa menggunakan sortperintah dalam skrip awk saya untuk mengurutkan para pemain dan jumlah mereka SAJA?


3
Mengingat komentar Anda pada jawaban, Anda tampaknya membingungkan skrip awk dan shell dalam pertanyaan Anda. Tampaknya Anda ingin melakukan pengurutan di dalam skrip awk Anda , bukan di skrip shell yang memintanya. Jika itu benar, silakan edit pertanyaan Anda dan ganti dua kemunculan 'shell' dengan 'awk'. Pada catatan terpisah: ya, awk memiliki fasilitas penyortiran, tetapi cukup terlibat: Anda harus menyimpan semua baris dalam array, dikunci pada bidang kedua, yang harus Anda ekstrak x, lalu setel PROCINFO["sorted_in"]ke nilai samar, kemudian output array. Saya tidak akan pergi ke sana.
zwets

1
Maksud saya: saya tidak akan pergi ke sana karena kesederhanaan ... | sort -k2,2.
zwets

@zwets Bagaimana saya menerapkan ...| sort -k2,2jika ada jalur lain yang perlu dicetak? Periksa pertanyaan yang diedit.
KM142646

Dengan echo-ing baris header dari shell, lalu jalankan awk | sortpipeline.
zwets

Jawaban:


12

Anda dapat menambah | sort -k2perintah Anda. Ini akan mengurutkan berdasarkan abjad pada kolom kedua.

Contoh:

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

hasil dalam

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

Sayangnya saya menggunakan skrip, dan perintah sortir akan dihaluskan dengan banyak output lainnya. Apakah ada cara untuk mengurutkan output {print x, $2}langsung dalam kode skrip? Saya mendapat pesan kesalahan saat melakukan perpipaan if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646

3
@ Kwoy: if(sum[x] > 500) {print x, $2}adalah kode awk sementara | sort -k2adalah perintah shell. Jelas Anda tidak dapat mencampur keduanya seperti itu karena mereka bahasa yang berbeda. Alih-alih, Anda perlu menerapkan sortperintah ke output penerjemah Awk yang menjalankan cuplikan kode Awk Anda. Jika Anda tidak tahu apa yang saya maksud, perluas pertanyaan Anda untuk memberi kami gambaran lengkap.
David Foerster

1
Anda sedang menulis skrip shell, bukan? Maka Anda memiliki dua opsi: 1. jalankan ./my-script.sh | sort -k2. 2. tambahkan `| sort -k2` ke baris skrip Anda yang menghasilkan output yang diberikan dalam pertanyaan Anda.
Wayne_Yux

@Wayne_Yux Silakan periksa suntingan yang dibuat untuk pertanyaan asli.
KM142646

Maka Anda mungkin perlu jawaban dari @steeldriver
Wayne_Yux

9

Meskipun saya tidak akan merekomendasikannya (mengingat kesederhanaan relatif dari memipipkan hasilnya melalui sortperintah eksternal ) Anda dapat melakukan ini setidaknya dengan versi terbaru dari GNU awk (minimal 4.0 IIRC), seperti yang dijelaskan pada Sorting Array Values ​​and Indices with gawk

Inilah cara Anda dapat mengimplementasikannya, dengan asumsi Anda memiliki data dalam array asosiatif di mana indeks berada Firstname Lastname. Pertama, Anda perlu mendefinisikan fungsi perbandingan khusus yang membagi indeks, membandingkan pertama Lastnamelalu (sebagai tie breaker) pada Firstnamemisalnya

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;
}

Sekarang Anda dapat menggunakan PROCINFO["sorted_in"]metode pengurutan array yang disebutkan dalam komentar oleh @zwets

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

Menyatukannya

#!/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];
}

Pengujian:

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

Dalam versi awk yang lebih kecil atau lebih lama, taruhan terbaik Anda mungkin adalah menyimpan data yang diindeks dengan Lastname Firstname, mengurutkan dengan yang konvensional asorti, lalu membagi dan menukar bidang indeks saat Anda melintasi array untuk mencetaknya:

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

Untuk sorthanya dengan bidang kedua yang dipisahkan spasi, gunakan kunci -k2,2:

... | sort -k2,2

secara default sortmelakukan penyortiran leksikografis.

Perhatikan bahwa, jika Anda tidak menyebutkan bidang terakhir untuk kunci pengurutan yaitu jika Anda hanya menggunakan -k2maka Anda mungkin tidak mendapatkan hasil yang diinginkan karena ini akan sortsesuai dengan semua bidang mulai dari yang kedua.

Periksa juga man sort.


Silakan periksa komentar pada posting Wayne untuk apa yang saya butuhkan
KM142646

1

Mencoba

awk -f myscript.awk | sort -k2

Di mana myscript.awk berisi perintah murni awk.

Jika skrip aktual Anda adalah skrip shell, Anda memiliki beberapa opsi termasuk

  • Output pipa melalui sortir. ./myscript.bash | sort -k2
  • Menulis ulang kode sebagai fungsi di dalam naskah
    Alih-alih

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

    Melakukan

    $ 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
    

Tetapi perhatikan, Anda juga dapat menerapkan struktur semacam itu pada do ... done daripada membuat fungsi.

    do
       echo $i
    done | sort

Mengapa mendefinisikan fungsinya?
zwets

@ zwets, membuatnya lebih mudah untuk memberi makan hasil kode arbitrer, termasuk struktur kontrol perulangan, melalui pipa. Ada kasus di mana itu tidak perlu, tetapi saya menemukan pola umum yang bermanfaat. Saya akan mengedit jawaban saya untuk menunjukkan ini.
RedGrittyBrick

1

Untuk mengurutkan data Anda untuk dicetak:

  • Misalkan Anda ingin mencetak bidang ke-2 (dipisahkan spasi) gunakan ini:

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

    misalnya:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Jika Anda ingin mencetak keseluruhan data.txttetapi diurutkan pada kolom 2, maka:

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

Gunakan logika ini dalam kebutuhan Anda.

Anda dapat menggunakan man sortuntuk fitur yang lebih menarik dari sort.


0

bagaimana dengan di bawah ini:

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

ini bekerja ketika saya diuji.


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

Untuk mengurutkan output ke file:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.