我想对由日期组成的行进行排序,但我在尝试弄清楚如何对行进行排序并保持行完整时遇到了麻烦。我也不明白如何使用管道对线条进行排序。
例如,我的脚本将其作为文本文件接收:
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 测试)