Làm thế nào để sử dụng sort trên một lệnh in awk?


8

Tôi có một vài lệnh trong một kịch bản awk tôi đang viết:

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

Đầu ra nào:

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

Làm cách nào tôi có thể sử dụng sortlệnh trong tập lệnh awk của mình để sắp xếp người chơi và số của họ CHỈ?


3
Đưa ra nhận xét của bạn về các câu trả lời, bạn có vẻ khó hiểu về kịch bản awkshell trong câu hỏi của bạn. Có vẻ như bạn muốn thực hiện việc sắp xếp trong tập lệnh awk của bạn chứ không phải trong tập lệnh shell gọi nó. Nếu đó là chính xác, thì vui lòng chỉnh sửa câu hỏi của bạn và thay thế hai lần xuất hiện của 'shell' bằng 'awk'. Một lưu ý riêng: có, awk có một cơ sở phân loại, nhưng nó khá liên quan: bạn phải lưu trữ tất cả các dòng trong một mảng, được khóa trên trường thứ hai của chúng, mà bạn sẽ cần trích xuất x, sau đó đặt thành PROCINFO["sorted_in"]giá trị mật mã, sau đó xuất mảng. Tôi sẽ không đến đó.
zwets

1
Ý tôi là: tôi sẽ không đến đó vì sự đơn giản ... | sort -k2,2.
zwets

@zwets Tôi sẽ triển khai như thế nào ...| sort -k2,2nếu có những dòng khác cần được in? Kiểm tra câu hỏi chỉnh sửa.
KM142646

Bằng cách echo-ing dòng tiêu đề từ shell, sau đó chạy awk | sortđường ống.
zwets

Câu trả lời:


12

bạn có thể thêm | sort -k2vào lệnh của bạn. Điều này sẽ sắp xếp theo thứ tự abc dựa trên cột thứ hai.

Thí dụ:

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

kết quả trong

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

Thật không may, tôi đang sử dụng một tập lệnh và lệnh sort sẽ được kết hợp với nhiều kết quả đầu ra khác. Có cách nào để sắp xếp đầu ra {print x, $2}trực tiếp trong mã script không? Tôi đang gặp lỗi khi đường ống if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646

3
@KMoy: if(sum[x] > 500) {print x, $2}là mã Awk trong khi | sort -k2là lệnh shell. Rõ ràng bạn không thể trộn lẫn hai thứ như thế bởi vì chúng là những ngôn ngữ khác nhau. Thay vào đó, bạn cần áp dụng sortlệnh cho đầu ra của trình thông dịch Awk chạy đoạn mã Awk của bạn. Nếu bạn không biết ý tôi là gì, hãy mở rộng câu hỏi của bạn để cung cấp cho chúng tôi bức tranh đầy đủ.
David Foerster

1
Bạn đang viết một kịch bản shell, phải không? Sau đó, bạn có hai lựa chọn: 1. chạy ./my-script.sh | sort -k2. 2. thêm `| sắp xếp -k2` vào dòng tập lệnh tạo ra đầu ra được đưa ra trong câu hỏi của bạn.
Wayne_Yux

@Wayne_Yux Vui lòng kiểm tra các chỉnh sửa được thực hiện cho câu hỏi ban đầu.
KM142646

Sau đó, bạn có thể cần câu trả lời từ @steel ấn
Wayne_Yux

9

Mặc dù tôi không khuyến nghị điều đó (với sự đơn giản tương đối của đường ống kết quả thông qua sortlệnh bên ngoài ), bạn có thể thực hiện điều này ít nhất với các phiên bản gần đây của GNU awk (ít nhất là 4.0 IIRC), như được mô tả tại Sắp xếp các giá trị và chỉ số mảng với gawk

Đây là cách bạn có thể thực hiện nó, giả sử bạn có dữ liệu trong một mảng kết hợp trong đó chỉ mục Firstname Lastname. Trước tiên, bạn cần xác định chức năng so sánh tùy chỉnh phân tách chỉ mục, trước tiên so sánh Lastnamesau đó (dưới dạng ngắt kết nối) trên Firstnameví dụ:

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

Bây giờ bạn có thể sử dụng PROCINFO["sorted_in"]phương pháp sắp xếp mảng được đề cập trong các nhận xét của @zwets

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

Đặt nó lại với nhau

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

Kiểm tra:

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

Trong các phiên bản awk ít hơn hoặc cũ hơn, cách tốt nhất của bạn có thể là lưu trữ dữ liệu được lập chỉ mục Lastname Firstnamethay vào đó, sắp xếp theo thông thường asorti, sau đó phân tách và trao đổi các trường của các chỉ mục khi bạn duyệt qua mảng để in:

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

Để sortchỉ bằng trường thứ hai được phân tách khoảng trắng, sử dụng khóa -k2,2:

... | sort -k2,2

theo mặc định sort, việc sắp xếp từ vựng.

Lưu ý rằng, nếu bạn không đề cập đến trường cuối cùng cho khóa sắp xếp, tức là nếu bạn chỉ sử dụng -k2thì bạn có thể không nhận được kết quả mong muốn vì điều này sẽ sorttheo tất cả các trường bắt đầu từ giây.

Cũng kiểm tra man sort.


Vui lòng kiểm tra nhận xét về bài đăng của Wayne để biết những gì tôi cần
KM142646

1

Thử

awk -f myscript.awk | sort -k2

Trong đó myscript.awk chứa các lệnh awk hoàn toàn.

Nếu tập lệnh thực tế của bạn là tập lệnh shell, bạn có một số tùy chọn bao gồm

  • Đầu ra ống thông qua sắp xếp. ./myscript.bash | sort -k2
  • Viết lại mã dưới dạng một hàm bên trong tập lệnh
    Thay vì

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

    Làm

    $ 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
    

Nhưng lưu ý rằng bạn cũng có thể áp dụng sắp xếp cho cấu trúc do ... thực hiện thay vì thực hiện một chức năng.

    do
       echo $i
    done | sort

Tại sao định nghĩa hàm?
zwets

@zwets, làm cho việc cung cấp kết quả của mã tùy ý dễ dàng hơn, bao gồm các cấu trúc điều khiển lặp, thông qua một đường ống. Có những trường hợp không cần thiết nhưng tôi thấy đó là một mô hình chung hữu ích. Tôi sẽ chỉnh sửa câu trả lời của tôi để chứng minh điều này.
RedGrittyBrick

1

Để sắp xếp dữ liệu của bạn để in:

  • Giả sử bạn muốn in trường thứ 2 (tách khoảng trắng) sử dụng:

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

    ví dụ:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Nếu bạn muốn in toàn bộ data.txtnhưng được sắp xếp trên cột 2, thì:

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

Sử dụng logic này trong yêu cầu của bạn.

Bạn có thể sử dụng man sortcho các tính năng thú vị hơn của sort.


0

những gì về bên dưới:

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

Nó hoạt động khi tôi thử nghiệm.


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

Để sắp xếp đầu ra cho một tệp:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.