如何在awk打印命令上使用排序?


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

如何在awk脚本中使用sort命令仅对玩家及其编号进行排序?


3
给定您对答案的评论,您似乎在问题中混淆了awkshell脚本。看来您希望在awk脚本中进行排序,而不是在调用它的shell脚本中进行排序。如果正确,请编辑您的问题,并用“ awk”替换两次出现的“ shell”。单独说明一下:是的,awk具有排序功能,但是它涉及到很多:您必须将所有行存储在数组中,并在其第二个字段中进行键控,您需要从第二个字段中提取该行x,然后将其设置PROCINFO["sorted_in"]为一个隐含值,然后输出数组。我不会去那里。
zwets

1
我的意思是:鉴于的简单性,我不会去那里... | sort -k2,2
zwets

@zwets ...| sort -k2,2如果需要打印其他行,我将如何实现?检查已编辑的问题。
KM142646 '16

通过echo在shell中添加标题行,然后运行awk | sort管道。
zwets

Answers:


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 '16

3
@KMoy:if(sum[x] > 500) {print x, $2}是Awk代码,| sort -k2而是shell命令。显然,您不能像这样将两者混用,因为它们是不同的语言。相反,您需要将该sort命令应用于运行Awk代码段的Awk解释器的输出。如果您不明白我的意思,请扩大您的问题以提供完整的信息。
David Foerster

1
您正在编写Shell脚本,对吗?然后,您有两个选择:1.运行./my-script.sh | sort -k2。2.添加`| 将-k2`排序到脚本行,该脚本行生成问题中给定的输出。
Wayne_Yux '16

@Wayne_Yux请检查对原始问题所做的编辑。
KM142646 '16

那么您可能需要来自@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仅由空格分隔的第二个字段,请使用key -k2,2

... | sort -k2,2

默认情况下sort按字典顺序进行排序。

请注意,如果您没有提及排序键的最后一个字段(即,如果您仅使用它),-k2则可能无法获得所需的结果,因为sort根据第二个字段开始的所有字段都会如此。

同时检查man sort


请检查韦恩的帖子上我需要的评论
KM142646 '16

1

尝试

awk -f myscript.awk | sort -k2

其中myscript.awk仅包含awk命令。

如果您的实际脚本是shell脚本,则可以选择以下几种方法:

  • 通过排序输出管道。 ./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"}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.