在AWK中按字段对行进行数字排序

在AWK中按字段对行进行数字排序,awk,Awk,我有一个包含这些字符的文本文件,其中我的分隔符/分隔符是##@##: 现在我想让它们按数字排序&按第三个字段升序。我读到可以使用bash命令sort,不幸的是,它只支持单个字符作为分隔符 最终,排序后的文件应与以下文件完全相同: Steve##@##Wozniak##@##Apple Inc.##@##12343 Bill##@##Gates##@##Microsoft Corp.##@##234213 Steve##@##Jobs##@##Apple Inc.##@##32421213 Tim

我有一个包含这些字符的文本文件,其中我的分隔符/分隔符是
##@##

现在我想让它们按数字排序&按第三个字段升序。我读到可以使用bash命令
sort
,不幸的是,它只支持单个字符作为分隔符

最终,排序后的文件应与以下文件完全相同:

Steve##@##Wozniak##@##Apple Inc.##@##12343
Bill##@##Gates##@##Microsoft Corp.##@##234213
Steve##@##Jobs##@##Apple Inc.##@##32421213
Tim##@##Cook##@##Apple Inc.##@##323345223
是否有一个排序修复程序,或者我可以使用awk执行此操作?

这里有一个(黑客的)想法。使用
awk
将数字字段添加到每行的开头,这样我们就可以使用
sort
对其进行排序,然后使用
sed
删除我们在第一步中添加的内容。诸如此类:

awk -vFS='##@##' '{print $4 "|" $0}' input | sort -n | sed -e 's/^[^|]*|//'
这里有一个(粗俗的)想法。使用
awk
将数字字段添加到每行的开头,这样我们就可以使用
sort
对其进行排序,然后使用
sed
删除我们在第一步中添加的内容。诸如此类:

awk -vFS='##@##' '{print $4 "|" $0}' input | sort -n | sed -e 's/^[^|]*|//'

解决方案使用
perl
,不需要其他命令

$ cat ip.txt 
Steve##@##Jobs##@##Apple Inc.##@##32421213
Bill##@##Gates##@##Microsoft Corp.##@##234213
abc##@##xyz##@##123 Corp.##@##234213
Steve##@##Wozniak##@##Apple Inc.##@##12343
Tim##@##Cook##@##Apple Inc.##@##323345223

$ perl -ne '($k)=/(\d+)$/; $h{$k} .= $_; END{foreach (sort {$a <=> $b} keys %h){print $h{$_}}}' ip.txt 
Steve##@##Wozniak##@##Apple Inc.##@##12343
Bill##@##Gates##@##Microsoft Corp.##@##234213
abc##@##xyz##@##123 Corp.##@##234213
Steve##@##Jobs##@##Apple Inc.##@##32421213
Tim##@##Cook##@##Apple Inc.##@##323345223
$cat ip.txt
史蒂夫·乔布斯、苹果公司、32421213
比尔•盖茨•微软公司234213
美国广播公司123公司234213
史蒂夫·沃兹尼亚克·苹果公司12343
蒂姆•库克•苹果公司323345223
$perl-ne'($k)=/(\d+)$/$h{$k}.=$\;END{foreach(sort{$a$b}键%h){print$h{${}}}ip.txt
史蒂夫·沃兹尼亚克·苹果公司12343
比尔•盖茨•微软公司234213
美国广播公司123公司234213
史蒂夫·乔布斯、苹果公司、32421213
蒂姆•库克•苹果公司323345223
  • 行尾的数字用作键
  • 输入行被附加到基于键的散列变量中,这样也可以处理具有相同键的多行
  • 处理完所有行后,将按数字对键进行排序,并打印出相应的值

解决方案使用
perl
,无需其他命令

$ cat ip.txt 
Steve##@##Jobs##@##Apple Inc.##@##32421213
Bill##@##Gates##@##Microsoft Corp.##@##234213
abc##@##xyz##@##123 Corp.##@##234213
Steve##@##Wozniak##@##Apple Inc.##@##12343
Tim##@##Cook##@##Apple Inc.##@##323345223

$ perl -ne '($k)=/(\d+)$/; $h{$k} .= $_; END{foreach (sort {$a <=> $b} keys %h){print $h{$_}}}' ip.txt 
Steve##@##Wozniak##@##Apple Inc.##@##12343
Bill##@##Gates##@##Microsoft Corp.##@##234213
abc##@##xyz##@##123 Corp.##@##234213
Steve##@##Jobs##@##Apple Inc.##@##32421213
Tim##@##Cook##@##Apple Inc.##@##323345223
$cat ip.txt
史蒂夫·乔布斯、苹果公司、32421213
比尔•盖茨•微软公司234213
美国广播公司123公司234213
史蒂夫·沃兹尼亚克·苹果公司12343
蒂姆•库克•苹果公司323345223
$perl-ne'($k)=/(\d+)$/$h{$k}.=$\;END{foreach(sort{$a$b}键%h){print$h{${}}}ip.txt
史蒂夫·沃兹尼亚克·苹果公司12343
比尔•盖茨•微软公司234213
美国广播公司123公司234213
史蒂夫·乔布斯、苹果公司、32421213
蒂姆•库克•苹果公司323345223
  • 行尾的数字用作键
  • 输入行被附加到基于键的散列变量中,这样也可以处理具有相同键的多行
  • 处理完所有行后,将按数字对键进行排序,并打印出相应的值

因为排序(1)只接受单个字符分隔符,所以您希望将分隔符字符串转换为排序可以识别的内容,但不是数据中显示的值。您的最佳选择是数据中无法显示的内容:不可打印的字符。一个合理的候选者是ASCII字段分隔符octal 034。当然,排序后必须恢复分隔符

如果使用bash,则可以通过八进制值直接访问字符,否则shell可能会有所不同。然后sed使其成为一个快照:

$ s=$'\034'
$ sed "s/##@##/$s/g" dat | sort -t $s -k4 -n | sed "s/$s/##@##/g"

Steve##@##Wozniak##@##Apple Inc.##@##12343
Bill##@##Gates##@##Microsoft Corp.##@##234213
Steve##@##Jobs##@##Apple Inc.##@##32421213
Tim##@##Cook##@##Apple Inc.##@##323345223

由于排序(1)只接受单个字符分隔符,因此您希望将分隔符字符串转换为排序可识别的内容,而不是数据中显示的值。您的最佳选择是数据中无法显示的内容:不可打印的字符。一个合理的候选者是ASCII字段分隔符octal 034。当然,排序后必须恢复分隔符

如果使用bash,则可以通过八进制值直接访问字符,否则shell可能会有所不同。然后sed使其成为一个快照:

$ s=$'\034'
$ sed "s/##@##/$s/g" dat | sort -t $s -k4 -n | sed "s/$s/##@##/g"

Steve##@##Wozniak##@##Apple Inc.##@##12343
Bill##@##Gates##@##Microsoft Corp.##@##234213
Steve##@##Jobs##@##Apple Inc.##@##32421213
Tim##@##Cook##@##Apple Inc.##@##323345223

这是标准方法,但使用
\t
而不是
|
作为分隔符,因为这是默认的
排序
分隔符,因此您可以告诉sort仅使用第一个字段(与顺序为
|
与其他字符的YMMV一样)也就是说,您可以在后面使用cut和它的默认分隔符:
awk-F'###@##'-v of s='\t'{print$4,$0}'input | sort-k1,1n | cut-f2-
。这是标准方法,但使用
\t
而不是
作为分隔符,因为这是默认的
排序
分隔符,因此您可以告诉sort只使用第一个字段(与顺序为
的YMMV和其他字符一样)也就是说,您可以在后面使用cut和它的默认分隔符:
awk-F'##@v of s='\t'{print$4,$0}input | sort-k1,1n | cut-f2-