[英]Error in sorting based on a specific column in bash
注意:假设输入文件的列由空格而不是制表符分隔,否则 dan 的注释 - sort -nt $'\t' -k3,3
- 就足够了
sort
允许我们指定字段终止符以及要排序的字段(以及可选的字段子字符串)。
如果我们将字段分隔符设置为换行符 ( \n
),则整行将变为单个字段。
从这里我们可以指定字段 #1 的子字符串作为排序依据; -k1.x,1.y
表示按字段 #1 从位置x
到位置y
排序(字段/行的第一个字符的位置为1
)。
样本输入:
$ cat animals.txt
1 2 3 4 5 6
123456789012345678901234567890123456789012345678901234567890
alpaca Intermediate Perl 2012 Schwatz, Randal
donkey Cisco IOS in a Nutshell 2005 Boney, James
horse Linux in a Nutshell 2009 Siever, Ellen
在哪里:
year
部分从位置36
到39
将所有这些都放入一个sort
调用中:
# sort numerically by year (ascending)
$ sort -t$'\n' -k1.36,1.39 -n animals.txt
donkey Cisco IOS in a Nutshell 2005 Boney, James
horse Linux in a Nutshell 2009 Siever, Ellen
alpaca Intermediate Perl 2012 Schwatz, Randal
# sort numerically by year (descending)
$ sort -t$'\n' -k1.36,1.39 -rn animals.txt
alpaca Intermediate Perl 2012 Schwatz, Randal
horse Linux in a Nutshell 2009 Siever, Ellen
donkey Cisco IOS in a Nutshell 2005 Boney, James
注意:假设所有行的year
都在同一位置(即文件的内容按照固定宽度方案进行格式化)
显然这种方法需要我们提前知道year
子串的位置; 有几种方法可以确定这个位置......一个想法,假设year
列总是第一次出现 4 位子字符串......使用bash
正则表达式匹配和BASH_REMATCH[]
数组来确定排列到 4 位数的year
,例如:
$ regex="^([^0-9]*)([0-9]{4}).*"
$ [[ $(head -1 animals.txt) =~ $regex ]] && typeset -p BASH_REMATCH
declare -ar BASH_REMATCH=([0]="alpaca Intermediate Perl 2012 Schwatz, Randal" [1]="alpaca Intermediate Perl " [2]="2012")
从这里我们看到BASH_REMATCH[1]
包含该行的内容,直到year
( 2012
用于alpaca
行); 现在我们获取BASH_REMATCH[1]
的长度并添加 +1/+3 以获得我们的x
和y
值:
$ (( x = ${#BASH_REMATCH[1]} + 1 ))
$ (( y = x + 3 ))
$ typeset -p x y
declare -- x="36"
declare -- y="39"
将这些变量插入到我们之前的sort
调用中:
# sort numerically by year (ascending)
$ sort -t$'\n' -k1.${x},1.${y} -n animals.txt
donkey Cisco IOS in a Nutshell 2005 Boney, James
horse Linux in a Nutshell 2009 Siever, Ellen
alpaca Intermediate Perl 2012 Schwatz, Randal
# sort numerically by year (descending)
$ sort -t$'\n' -k1.${x},1.${y} -rn animals.txt
alpaca Intermediate Perl 2012 Schwatz, Randal
horse Linux in a Nutshell 2009 Siever, Ellen
donkey Cisco IOS in a Nutshell 2005 Boney, James
注意:在多行具有相同日期的情况下,OP 没有定义二级排序要求,但扩展这个答案以包括二级(和三级?)排序要求应该不会太难
尝试添加逗号之类的分隔符,因为从那里您将能够使用带有-t
参数的sort
命令并指定给定的字段分隔符。
要查找并用分隔符替换字符,我会使用cat animals.txt | sed {insert the pattern}
cat animals.txt | sed {insert the pattern}
。
根据您共享的文件,您可以尝试在第一个单词之后以及数值之前和之后添加分隔符。
注意:假设输入文件的列由空格而不是制表符分隔,否则 dan 的注释 - sort -nt $'\t' -k3,3
- 就足够了
如果GNU awk
可用,我们可以让awk
找到year
子字符串的索引,然后为我们对输出进行排序。
样本输入:
$ cat animals.txt
1 2 3 4 5 6
123456789012345678901234567890123456789012345678901234567890
alpaca Intermediate Perl 2012 Schwatz, Randal
donkey Cisco IOS in a Nutshell 2005 Boney, James
horse Linux in a Nutshell 2009 Siever, Ellen
在哪里:
year
部分从位置36
到39
一个GNU awk
想法:
awk '
FNR==1 { x=match($0, /[0-9]{4}/) } # find index of the "year" substring in the 1st line of input; assumes the "year" is the 1st occurrence of a 4-digit substring
{ arr[substr($0,x,4)][FNR]=$0 } # populate 2-dimensional array using "year" and row number (FNR) as indexes
END { PROCINFO["sorted_in"]="@ind_num_asc" # sort indexes as numbers in "asc"ending order
for (i in arr)
for (j in arr[i])
print arr[i][j]
}
' animals.txt
这会产生:
donkey Cisco IOS in a Nutshell 2005 Boney, James
horse Linux in a Nutshell 2009 Siever, Ellen
alpaca Intermediate Perl 2012 Schwatz, Randal
如果我们将排序顺序从@ind_num_asc
更改为@ind_num_desc
,我们可以按year
降序生成输出,即:
alpaca Intermediate Perl 2012 Schwatz, Randal
horse Linux in a Nutshell 2009 Siever, Ellen
donkey Cisco IOS in a Nutshell 2005 Boney, James
笔记:
GNU awk
PROCINFO["sorted_in"]
功能需要GNU awk
一种方法是使用sed
将年份复制到每行的开头,对结果输出进行数字sort
,然后在每行的开头删除年份:
sed 's/^.*[[:space:]]\([12][09][0-9][0-9]\)[[:space:]].*$/\1 &/' animals.txt \
| sort -n | sed 's/^.....//'
问题中带有示例animals.txt
的输出是:
oryx Writing Word Macros 1999 Roman, Steven
donkey Cisco IOS in a Nutshell 2005 Boney, James
snail SSH, The Secure Shell 2005 Barrett, Daniel
horse Linux in a Nutshell 2009 Sievers, Ellen
python Programming Python 2010 Lutz, Mark
alpaca Intermediate Perl 2012 Schwartz, Randal
robin MySQL High Availability 2014 Bell, Charles
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.