按日期排序,列数可变

  • 本文关键字:日期 排序 bash shell unix
  • 更新时间 :
  • 英文 :


我想对由日期组成的行进行排序,但我在尝试弄清楚如何对行进行排序并保持行完整时遇到了麻烦。我也不明白如何使用管道对线条进行排序。

例如,我的脚本将其作为文本文件接收:

asdsa 24 asdsa 3 3000 054217542 30.3.2016
asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
dsasda 23 dsada 4 3200 537358234 6.3.2016

我想逐行阅读:

while read line; do
done < "$1"

并在里面按日期对行进行排序。如何在逐个读取行时将行排序为文件中的行?

如果我这样做怎么办:

#!/bin/bash
PATH=${PATH[*]}:.
#filename: testScript

while read line; do
    arr=( $line )
    num_of_params=`echo ${#arr[*]}`
    echo $line | sort -n -k$num_of_params
    num_of_params=0
done < "$1"

我的问题是我实际上将每一行都发送给自己进行排序,而不是将行全部发送到一起,但我不知道任何其他方法可以做到这一点(不使用临时文件,我不打算使用其中任何一个)。

输出:

asdsa 24 asdsa 3 3000 054217542 30.3.2016
asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
dsasda 23 dsada 4 3200 537358234 6.3.2016

期望输出:

asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
dsasda 23 dsada 4 3200 537358234 6.3.2016
asdsa 24 asdsa 3 3000 054217542 30.3.2016

如您所见,它不起作用。

我该如何解决这个问题?

这是一个使用带有awk和cut的施瓦茨变换的解决方案:

awk '{split($NF,arr,"."); printf("%d%02d%02dt%sn",arr[3],arr[2],arr[1],$0)}' infile |
sort -k 1,1 | cut -f 2-

awk 部分首先将记录的最后一个字段($NF(日期))拆分为一个数组arr

split($NF,arr,".")

第二部分打印带有重新格式化日期的行:首先是年份,然后是月份和日期,后两部分将零填充到两位数:

printf("%d%02d%02dt%sn",arr[3],arr[2],arr[1],$0)

其输出如下所示:

20160330        asdsa 24 asdsa 3 3000 054217542 30.3.2016
20140102        asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
20160306        dsasda 23 dsada 4 3200 537358234 6.3.2016

现在我们可以管道连接到sort并使用第一个字段:

sort -k 1,1

导致

20140102        asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
20160306        dsasda 23 dsada 4 3200 537358234 6.3.2016
20160330        asdsa 24 asdsa 3 3000 054217542 30.3.2016

最后,我们再次删除插入的字段 cut ,只保留第二个字段的所有内容:

cut -f 2-

导致

asdsadsa 25 asdsadsaa 5 4500 534215365 2.1.2014
dsasda 23 dsada 4 3200 537358234 6.3.2016
asdsa 24 asdsa 3 3000 054217542 30.3.2016

Bash解决方案

如果我们只想使用 Bash 而不是 awk,我们可以这样做:

#!/bin/bash
# Read each line into an array 'line'
while read -r -a line; do
    # Find the number of array elements
    nel=${#line[@]}
    # Assign the last element of the array to 'date'
    date=${line[nel-1]}
    # Extract the month from the date with parameter expansion
    month=${date#*.}
    month=${month%.*}
    # Year and day need only one expansion step, which is done here directly
    printf "%d%02d%02dt%sn" "${date##*.}" "$month" "${date%%.*}" "${line[*]}"
# Pipe result to sort, then remove the first column with cut
done < infile | sort -k 1,1 | cut -f 2-

总体思路完全相同:我们添加一个包含重新格式化日期的额外列,按该列排序,然后再次删除它。

试试

awk -F"[. ]*" '
{
   printf "%d%02d%02d %sn", $NF, $(NF-1), $(NF-2), $0
}' test | sort -n | cut -c10-

当然test是您文件的名称...这取决于日期是您在初始帖子中指定的格式的每一行的最后一部分。 (在 FreeBSD 上使用 (n)awk 测试)

相关内容

  • 没有找到相关文章

最新更新