文中:
35 EAST 23rd Street SOUTH AFRICA 5 600 5000000 6
83 NORTH YELLOWLIGHT AVENUE SOUTH AFRICA 4 700 7000000 5
777 NEW AVENUE SAUDIA 2 900 5000000 3
FIVE VISA ROAD MEXICO 3 300 500000 7
450 JACKSON BLVD USA 3 1500 300000 4
25 QUEENS ROAD SOUTH SOUTH AFRICA 1 900 400000 3
如何使用gawk
orawk
和sort
来确保只有南非作为倒数第二列的升序输出?
我试过了 :
awk -F. '/SOUTH AFRICA/ {print }' | sort -n -k5
但它似乎不起作用。
答案1
简而言之,您需要首先修复原始输入,它一开始就不一致,从而在稍后尝试运行命令时导致问题。
以下是如何解决此问题的详细信息:
检查您发布的内容
首先,我们来看看问题所在。例如,如果我们复制您发布的内容并将其另存为original_file.tsv
:
35 EAST 23rd Street SOUTH AFRICA 5 600 5000000 6
83 NORTH YELLOWLIGHT AVENUE SOUTH AFRICA 4 700 7000000 5
777 NEW AVENUE SAUDIA 2 900 5000000 3
FIVE VISA ROAD MEXICO 3 300 500000 7
450 JACKSON BLVD USA 3 1500 300000 4
25 QUEENS ROAD SOUTH SOUTH AFRICA 1 900 400000 3
乍一看显得整齐、得体。不幸的是,当我们像这样仔细查看时cat -A
,您将在命令提示符上看到:
$ cat -A original_file.tsv
35 EAST 23rd Street^I^ISOUTH AFRICA^I^I5^I600^I5000000^I^I6 $
83 NORTH YELLOWLIGHT AVENUE^ISOUTH AFRICA^I4^I700^I7000000^I^I5 $
777 NEW AVENUE^ISAUDIA^I^I2^I900^I5000000^I^I3 $
FIVE VISA ROAD^I^IMEXICO^I^I3^I300^I500000^I^I7 $
450 JACKSON BLVD^I^IUSA^I^I3^I1500^I300000^I^I4 $
25 QUEENS ROAD SOUTH^I^ISOUTH AFRICA^I^I1^I900^I400000^I^I3$
- 意思
^I
是“这里有一个选项卡” - 意思
$
是“这是该行的结尾”
这立即揭示了不一致之处,例如:
- 第 1 行:
35 EAST 23rd Street
选项卡选项卡SOUTH AFRICA
... - 第 2 行:
83 NORTH YELLOWLIGHT AVENUE
选项卡SOUTH AFRICA
...
一行有两个选项卡分隔字段 1 和字段 2,下一行只有一个选项卡。每行都不相同。
sort
但是,当每行如此不同时,如果每行上的分隔符或定界符的排列不一致,则无法在此处正确数据。
清理版本
看起来唯一的问题(至少在这个示例中)是双选项卡的外观,而实际上它应该是单选项卡。因此,我们应该尽可能尝试使用工具,而不是手动编辑来清理它。这里我们可以使用sed
它来清理它,并将结果保存到文件中,例如我们可以调用 results clean_file.tsv
:
$ sed 's/\t\t/\t/g;s/ $//g' original_file.tsv > clean_file.tsv
s/\t\t/\t/g
搜索两个选项卡并将其替换为一个;
在 sed 参数中分隔多个命令s/ $//g
因为某些行尾似乎有一个尾随空格,所以这里将其删除>
文件重定向将sed
输出保存到文件中,我们称之为clean_file.tsv
clean_file.tsv
好像:
35 EAST 23rd Street SOUTH AFRICA 5 600 5000000 6
83 NORTH YELLOWLIGHT AVENUE SOUTH AFRICA 4 700 7000000 5
777 NEW AVENUE SAUDIA 2 900 5000000 3
FIVE VISA ROAD MEXICO 3 300 500000 7
450 JACKSON BLVD USA 3 1500 300000 4
25 QUEENS ROAD SOUTH SOUTH AFRICA 1 900 400000 3
我们可以再次使用cat -A
但现在在我们的clean_file.tsv
:
35 EAST 23rd Street^ISOUTH AFRICA^I5^I600^I5000000^I6$
83 NORTH YELLOWLIGHT AVENUE^ISOUTH AFRICA^I4^I700^I7000000^I5$
777 NEW AVENUE^ISAUDIA^I2^I900^I5000000^I3$
FIVE VISA ROAD^IMEXICO^I3^I300^I500000^I7$
450 JACKSON BLVD^IUSA^I3^I1500^I300000^I4$
25 QUEENS ROAD SOUTH^ISOUTH AFRICA^I1^I900^I400000^I3$
我们确实看到现在一切都是一致的,如果我们仔细计算它们,现在每行都有相同数量的字段(此处为 6),以及相同数量的选项卡(此处为 5)作为字段分隔符或字段定界符。
awk,排序
现在我们已经clean_file.tsv
有了正确格式化的输入,我们现在可以运行命令,并查看:
$ awk '/SOUTH AFRICA/ {print }' clean_file.tsv | sort -t $'\t' -k5,5n
25 QUEENS ROAD SOUTH SOUTH AFRICA 1 900 400000 3
35 EAST 23rd Street SOUTH AFRICA 5 600 5000000 6
83 NORTH YELLOWLIGHT AVENUE SOUTH AFRICA 4 700 7000000 5
-F
与原始命令相比,被删除,因为用于-F
指定字段分隔符,此处不需要,因为awk
不执行任何字段操作,并且仅在此处用于打印SOUTH AFRICA
其中匹配的行-t $'\t'
指定字段分隔符为制表符。-k5,5
从第 5 列到第 5 列排序,因为在本例中您想要倒数第二列,而这里的第 5 列是这个 6 列数据样本中的倒数第二列n
表示数字排序。由于默认是升序,因此我们不需要进一步指定任何内容。
因此,通过清理原始数据并运行此awk
和sort
,您现在将能够找到SOUTH AFRICA
条目并按第五个字段升序对它们进行排序。
答案2
这里有两个基本问题:
- 您提供的内容没有字段分隔符,因此“第 5 列”没有意义。您必须编辑数据(例如,在列之间使用分号)以使“列”的概念有意义。我通常使用制表符作为列分隔符,但您可以使用数据中未出现的任何字符。
- 您需要告诉 sort 字段分隔符是什么。
编辑数据后,您可以执行我认为您要求的操作,如下所示:
% grep "SOUTH AFRICA" file | sort "-t;" -k5n
(假设“文件”包含您的数据)。这给出了以下输出:
25 QUEENS ROAD SOUTH;SOUTH AFRICA;1;900;400000;3
35 EAST 23rd Street SOUTH AFRICA;5;600;5000000;6
83 NORTH YELLOWLIGHT AVENUE;SOUTH AFRICA;4;700;7000000;5
如果您想确保南非仅在第二列中,您可以这样做:
% awk '-F;' '$2 == "SOUTH AFRICA"' file | sort '-t;' -k5n