【问题标题】:Piping awk through to sort doesn't sort correctly通过管道 awk 进行排序不能正确排序
【发布时间】:2015-12-04 10:02:53
【问题描述】:

假设有一个listing.dat 文件(位于:http://pastebin.com/gWkJS2fH

以下语句将 egrep 用于一个城市,将其通过管道传递给 awk,后者将查找任何选项卡并分成列。然后我将这些数据通过管道进行排序,这不会按升序对任何列进行排序。

我知道原因是标签造成的,但我不知道为什么或如何解决它。

egrep Toronto listing1.dat | gawk -F "[\t]+" '($3 >= 2) && ($4 >= 500) && ($5 <= 900000) && ($6 <= 5)' | sort -nk5

这应该按价格升序对结果进行排序。

任何想法我能做什么?

【问题讨论】:

  • 管道中的第一个命令基本被忽略,因为您为 gawk 命令指定了一个输入文件。这是我发现的第一件事,其他部分我没有检查。
  • 是的,你是对的!我昨晚确实发现了这一点,但从我的终端复制了一份旧的声明副本。感谢您指出这一点。
  • @4ae1e1 不,egrep 被忽略,所以它没有按城市过滤,但排序问题仍然存在。
  • 不要让我们去查看其他网站来查找您的数据,只需编辑您的问题以包含几行简短的示例输入和预期输出。
  • 非常有帮助的@EdMorton。

标签: linux bash sorting awk


【解决方案1】:

这里的问题是gawk 没有将这些行转换出来;地址和城市有时会被多个标签分隔。

您想要的是将输出字段分隔符设置为单个选项卡。现在 sort 将找到正确的列。我就是这样写的:

gawk '
        BEGIN{FS="\t+"
        OFS="\t"}
    /Toronto/ && \
    $3 >= 2 && \
    $4 >= 500 && \
    $5 <= 900000 && \
    $6 <= 5 && \
    $1=$1' data | sort -nt$'\t' -k5

为一些 cmets 编辑:

  • 在 BEGIN 块中设置字段分隔符和输出字段分隔符
  • 将城市名称设置为条件列表中的匹配器
  • $1=$1 添加到条件中。这具有“重新计算”行的效果,因此输入字段分隔符将替换为输出字段分隔符。
  • 需要一些技巧来让sorttab 作为分隔符。 $'\t' 可能并非在所有 shell 上都可用,但应该是合理的标准。

编辑 2 以删除条件中不必要的 ()

【讨论】:

  • 这太棒了,它是我最接近我需要的东西。唯一的问题是格式已被删除。感谢您的帮助
  • 很高兴能提供帮助。请考虑接受/支持答案。
【解决方案2】:

AWK doesn't work in Bash Script 中所述,首先摆脱不需要的 grep。您的排序可能需要“-b”,意思是忽略前导空格;手册页:http://ss64.com/bash/sort.html.

【讨论】:

  • 我需要 egrep,因为我不知道如何使用 gawk 过滤城市。 -b 对排序没有影响,不管有没有 egrep。
  • 我在您之前的帖子中向您展示过:awk -F "[\t]+" 'IGNORECASE = 1;/'$city'/&amp;&amp;($3 &gt;= '$minbed')&amp;&amp;($4 &gt;= '$minsqft')&amp;&amp;($5 &lt;= '$maxprice')&amp;&amp;($6 &lt;= '$maxweeks')';
【解决方案3】:
awk '$(NF-3)>=2&&$(NF-2)>=500&&$(NF-1)<=900000&&$NF <=5{++j;a[j]=$0;b[j]=$(NF-1)}END{asort(b,c);for(i in c){for(k in b)if(b[k]==c[i]){print a[k];delete b[k]}}}' file
450 West 33rd Street            Toronto         2       890     400000          1
11777 Mississippi Avenue        Toronto         2       890     400000          2
266 King Street West            Toronto         2       840     450000          1
4802 Fifth Avenue               Mississauga     3       1100    450000          5
4500 Wilshire Blvd              Vaughn          3       1420    500000          4
555 Broadway                    Toronto         2       840     500000          4
2213 Mt. Vernon Avenue          Vaughn          2       890     500000          4
1145 17th Street                Toronto         2       790     500000          3
100 Universal City Plaza        Toronto         2       890     580000          1
122 Sherbourne Street           Vaughn          2       690     650000          4
401 Mercer Street               Markham         2       890     700000          4
1416 North LaBrea Avenue        Markham         4       1890    880000          4
One Lincoln Plaza               Toronto         2       980     900000          1

【讨论】:

    【解决方案4】:

    我只是想告诉你我的意思是什么,如果你听从我关于发布示例输入/输出的建议,你会得到更好的答案,这里有一个例子:

    $ cat tst.awk
    BEGIN { FS="\t+" }
    ($2=="Toronto") && ($3>=2) && ($4>=500) && ($5<=900000) && ($6<=5) {
        hits[$5][$0]
    }
    END {
        PROCINFO["sorted_in"] = "@ind_num_asc"
        for (i in hits) {
            for (j in hits[i]) {
                print j
            }
        }
    }
    
    $ awk -f tst.awk file
    450 West 33rd Street            Toronto         2       890     400000          1
    11777 Mississippi Avenue        Toronto         2       890     400000          2
    266 King Street West            Toronto         2       840     450000          1
    555 Broadway                    Toronto         2       840     500000          4
    1145 17th Street                Toronto         2       790     500000          3
    100 Universal City Plaza        Toronto         2       890     580000          1
    One Lincoln Plaza               Toronto         2       980     900000          1
    

    请注意,格式已保留,您不需要任何外部工具,如 grep 或排序,也不需要管道。它还可以防止单词Toronto 出现在错误的上下文中,例如当地址为27 Toronto Ave, London27 London Ave, New York 时,请尝试您接受的答案(当您想搜索York 时)。

    以上使用 GNU awk 4.* 表示sorted_in

    【讨论】:

      【解决方案5】:
      egrep Toronto listing1.dat | gawk -F "\t+" '{if (($3 >= 2) && ($4 >= 500) && ($5 <= 900000) && ($6 <= 5)) {printf $5 "\t"; print}}' | sort -nk1 | cut -f 2-
      

      这会做一些事情:

      1) 它将第 5 个字段的副本添加到行首,后跟一个制表符。

      2) 排序现在很简单,因为您只需要基于单选项卡分隔对第一列进行排序。这会保留行的其余部分中可变数量的选项卡,使其看起来漂亮且对齐(如果需要)。

      3) 只需使用cut 保留从第二个字段开始的所有内容(即删除您添加的第一列)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-13
        • 2014-06-04
        • 2021-09-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        • 1970-01-01
        相关资源
        最近更新 更多