【问题标题】:How do I sort input with a variable number of fields by the second-to-last field?如何按倒数第二个字段对具有可变数量字段的输入进行排序?
【发布时间】:2016-03-11 12:04:08
【问题描述】:

编者注:原题提到tabs作为字段分隔符。

在诸如

这样的文本中
500 east 23rd avenue Toronto 2 890 400000 1 
900 west yellovillage blvd Mississauga 3 800 600090 3

如何按倒数第二列的升序排序?

编者注:OP 后来提供了另一个示例输入行,500 Jackson Blvd Toronto 3 700 40000 2,其中仅包含 8 个空格分隔的输入字段(与 9以上),揭示了在输入中处理可变个字段的需要。

【问题讨论】:

  • info sortman sort
  • 简答 sort -n -k 8 <path/to/file.txt 按每行中的第 8 个键(字段)进行数字排序。
  • 标签在哪里?字段的数量是否像示例中那样保持不变,或者您是否可以拥有诸如“899 edmonton street montreal 9 499 333222 9”之类的项目(半随机地凭空提取名称和数字)。它没有北/南/东/西指示符,因此它以 8 个字段而不是 9 个结束。如果该结构没有固定数量的字段,则您必须比它更努力地工作。实际上,您可能需要重新处理数据,以便可以使用 sort 命令拆分字段以便更轻松地处理,将数字和城市与街道地址以及彼此分开。
  • 500 Jackson Blvd Toronto 3 700 40000 2 900 yellowvillage avenue road Mississauga 3 800 600090 3. 555 calway road Toronto 2 840 500000 4 在这种情况下,倒数第二列表示公里,但也有在各自的行中有不同的列号,那么如何按倒数第二列的升序对其进行排序。这是我的问题

标签: linux sorting unix awk scripting


【解决方案1】:

我建议查看“man sort”。

您将看到如何指定字段分隔符以及如何指定应用作排序键的字段索引。

【讨论】:

  • 恐怕这不是一个好的答案。您至少应该建议如何使用 sort 选项处理最后一个字段。您可能还会提到如何利用制表符分隔符,同时询问它们在样本数据中的位置。
【解决方案2】:

你可以使用sort -k 2

例如:

echo -e '000 west \n500 east\n500 east\n900 west' | sort -k 2

结果是:

500 east
500 east
900 west
000 west

您可以在 sort 的手册页中找到更多信息。看看手册页的结尾。在作者之前你有一些有趣的信息:)

再见

【讨论】:

  • -k 8 不会更近吗?
【解决方案3】:

注意:有几个可能独立的问题:

更新:问题 C 是相关问题。

  • 问题 A:正如问题标题所暗示的那样:如何使用制表符 (\t) 作为字段分隔符? p>

  • 问题 B:在给定 固定 数字的情况下,如何在不预先知道该字段的特定索引的情况下按倒数第二个字段对输入进行排序字段?

  • 问题 C:如果给定 变量 数字,如何在不知道该字段各自索引的情况下按倒数第二个字段对输入进行排序字段?


问题 A 的答案:

sort-t 选项允许您指定字段分隔符。 默认情况下,sort 使用任何行内部空白作为分隔符。

假设 Bash、Ksh 或 Zsh,您可以使用 ANSI C-quoted string ($'...') 指定单个选项卡作为字段分隔符 ($'\t'):

sort -t $'\t' -n -k8,8 file # -n sorts numerically; omit for lexical sorting

问题 B 的答案:

注意:这假设所有输入行都有相同个字段,并且输入来自文件file

 # Determine the index of the next-to-last column, based on the first
 # line, using Awk:
 nextToLastColNdx=$(head -n 1 file | awk -F '\t' '{ print NF - 1 }')

 # Sort numerically by the next-to-last column (omit -n to sort lexically):
 sort -t $'\t' -n -k$nextToLastColNdx,$nextToLastColNdx file

注意:要按单个字段排序,请始终将其也指定为end字段(例如,-k8,8),如上所述,因为sort,仅给定一个开始字段索引(例如,-k8),从指定字段到行的其余部分进行排序。


问题 C 的答案:

注意:这假设输入行可能有一个可变个字段,并且在每一行上该行的倒数第二个字段应该起作用作为排序字段;输入来自文件file:

awk '{ printf "%s\t%s\n", $(NF-1), $0 }' file |
  sort -n -k1,1 | # omit -n to perform lexical sorting
    cut -f2-
  • awk 命令提取每行的倒数第二个字段,并将其添加到输出时的输入行,用制表符分隔。
  • 结果按第一个字段(即每个输入行的倒数第二个字段)排序。
  • 最后,人工添加的排序字段再次被删除,使用cut

【讨论】:

  • 500 east 23rd avenue Toronto 2 890 400000 1 900 westyyrovillage blvd street Mississauga 3 800 600090 3. 在这种情况下,您如何对倒数第二个进行排序,因为它不再是两条线上的第 8 列
  • 谢谢。这确实对我帮助很大,但是,这个特定的短语“%s\t%s\n”是什么意思,因为我似乎在练习或寻求帮助时都看不到它
  • @biggie: "%s\t%s\n" 是 Awk 的 printf 函数的格式字符串,它告诉它如何格式化其参数:%s 表示第一个参数并按原样打印(作为字符串),后跟 \t - 一个制表符 -,后跟第二个参数原样(%s 再次),以 \n 结束,一个换行符。实际上,倒数第二个字段值($(NF-1)NF 表示行上的字段数)首先打印,然后是一个制表符,然后是输入行原样 ($0) .
  • 好的,那么如果用户要在脚本中输入输入会怎样。例如上例中的 Mississauga,我们希望 awk 根据 $user_input 的变量对其进行过滤,并按倒数第二列排序?
  • @biggie:我会在这里给出一个快速的答案,但是 - 为了让您的问题和答案也对其他人有用,这就是本网站的目的 - 请 (a) 定义您的下次更准确地提问,并且(b)以后不要扩大问题的范围。 awk -v user_input="$user_input" '$0 ~ user_input { … (其余同上);这仅匹配包含 $user_input, anywhere 值的行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2017-11-13
  • 2013-03-17
  • 2011-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多