awk:按字符串分组,然后按字符串的子字符串排序

时间:2016-08-17 23:16:01

标签: shell sorting unix awk substring

假设我们有以下文件:

-rw-r--r-- 1 user group      120 Aug 17 18:27 A.txt
-rw-r--r-- 1 user group      155 May 12 12:28 A.txt
-rw-r--r-- 1 user group      155 May 10 21:14 A.txt
-rw-rw-rw- 1 user group      700 Aug 15 17:05 B.txt
-rw-rw-rw- 1 user group       59 Aug 15 10:02 B.txt
-rw-r--r-- 1 user group      180 Aug 15 09:38 B.txt
-rw-r--r-- 1 user group      200 Jul  2 17:09 C.txt
-rw-r--r-- 1 user group     4059 Aug  9 13:58 D.txt

在时间戳中只考虑HH:MM(即忽略时间戳的日期/日期部分),我想对此列表进行排序,以选择每个文件名的最大和最小时间戳。 因此,我们希望按最后一列进行分组并得到min&最大HH:MM。 请假设我的输入数据中允许使用文件名重复项。 在awk代码中,我特别坚持分组,然后先由HH排序,然后是MM。 我们期望的输出格式为:

Filename | Min HHMM | Max HHMM
A.txt 12:28 21:14 
C.txt 17:09 17:09

.. (或提供此详细信息的任何其他输出格式) 你能帮忙吗...天啊。

3 个答案:

答案 0 :(得分:1)

尝试:

awk '{if ($8<min[$9] || !min[$9])min[$9]=$8; if ($8>max[$9])max[$9]=$8} END{for (f in min)print f,min[f],max[f]}' file | sort

实施例

$ cat file
-rw-r--r-- 1 user group      120 Aug 17 18:27 A.txt
-rw-r--r-- 1 user group      155 May 12 12:28 A.txt
-rw-r--r-- 1 user group      155 May 10 21:14 A.txt
-rw-rw-rw- 1 user group      700 Aug 15 17:05 B.txt
-rw-rw-rw- 1 user group       59 Aug 15 10:02 B.txt
-rw-r--r-- 1 user group      180 Aug 15 09:38 B.txt
-rw-r--r-- 1 user group      200 Jul  2 17:09 C.txt
-rw-r--r-- 1 user group     4059 Aug  9 13:58 D.txt
$ awk '{if ($8<min[$9] || !min[$9])min[$9]=$8; if ($8>max[$9])max[$9]=$8} END{for (f in min)print f,min[f],max[f]}' file | sort
A.txt 12:28 21:14
B.txt 09:38 17:05
C.txt 17:09 17:09
D.txt 13:58 13:58

警告

您的输入看起来像是由ls生成的。 如果是这样,请注意ls的输出具有无数的特性和兼容性问题。 ls的作者建议不要解析ls的输出。

代码如何工作

awk隐式循环遍历每一行输入。此代码使用两个关联数组。 min会跟踪每个文件名的最短时间。 max跟踪最大值。

  • if ($8<min[$9] || !min[$9])min[$9]=$8

    如果当前行的时间min小于此文件名{1}}之前的时间,则会更新$8

  • $9

    如果当前行的时间if ($8>max[$9])max[$9]=$8大于此文件名{1}}之前的时间,则会更新max

  • $8

    这将打印出每个文件名的结果。

  • $9

    这会将输出分类为美观的形式。

答案 1 :(得分:1)

类似Matrix matInit(int m, int n) { Matrix bar; bar.ncols = n; bar.col = new Vector[n]; // use n instead m for consistency for (int i=0;i<n;i++) { bar.col[i].els = new float[m]; // add this line to allocate arrays for (int k=0;k<m;k++) { bar.col[i].els[k]=0; } } return bar; }

awk

请注意,打印标题和管道数据以在awk中排序会将标题保留在第一行。

答案 2 :(得分:0)

$ cat > test.awk
BEGIN {
    min["\x00""Filename"]="Min_HHMM"OFS"Max_HHMM" # set header in min[], preceded by NUL
}                                                 # to place on top when ordering (HACK)
!($9 in min)||min[$9]>$8 {                        # if candidate smaller than current min
    min[$9]=$8                                    # set new min
}
max[$9]<$8 {
    max[$9]=$8                                    # set new max
} 
END {
    PROCINFO["sorted_in"]="@ind_str_asc"          # set array scanning order for for loop
    for(i in min) 
        print i,min[i],max[i]
}
$ awk -f test.awk file
Filename Min_HHMM Max_HHMM
A.txt 12:28 21:14
B.txt 09:38 17:05
C.txt 17:09 17:09
D.txt 13:58 13:58

BEGIN hack可以在print块的开头用静态END替换:

print "Filename"OFS"Min_HHMM"OFS"Max_HHMM";