使用 Linux 命令“sort”按日期列排序的 Shell 脚本

使用 Linux 命令“sort”按日期列排序的 Shell 脚本

我有一个名为 session.log 的文件,它包含一些文本数据。第一列包含序列号。第二列包含用户名。第三列包含上次登录日期。第四列包含结果。

一名用户多次登录。我需要找到每个唯一用户的上次登录日期。所以我写了一个shell脚本。输出将显示每个唯一用户(第二列)的最新登录日期(第三列)的行。输出不应多次包含相同的用户名。

$ cat 会话.log
1 u1 2018-05-19 通过
2 u2 2018-06-15 通过
3 u3 2018-05-18 通过
4 u4 2018-05-17 通过
5 u2 2018-05-14 通过
6 u4 2018-07-11 通过
7 U1 2018-05-16 通过
8 u3 2018-05-13 通过
9 U1 2018-08-12 通过
10 u1 2018-05-10 通过

我尝试过的:

( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt
for line in $(cat "store.txt")
do
    touch "$line.txt"
    grep "$line" session.log > "$line.txt"
    temp=$(sort -k3 "$line.txt" | awk 'END{print}')
    echo $temp > "$line.txt"
    cat "$line.txt"
done

输出

$ ./sort.sh
9 U1 2018-08-12 通过
2 u2 2018-06-15 通过
3 u3 2018-05-18 通过
6 u4 2018-07-11 通过

shell 脚本适用于日期格式 (yyyy-mm-dd) 和 (yyyy/mm/dd)。有没有更好的代码来完成相同的工作?使用awk我们如何做到这一点?

编辑:

$ cat sort.sh
( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt
for line in $(cat "store.txt")
do
    #touch "$line.txt"
    grep "$line" session.log > "$line.txt"
    echo $(sort -k3 "$line.txt" | awk 'END{print}')
    #temp=$(sort -k3 "$line.txt" | awk 'END{print}')
    #echo $temp > "$line.txt"
    #cat "$line.txt"
done
rm -f store.txt

答案1

$ sort -k 3,3r session.log | awk '!seen[$2]++ { print }'
9 u1 2018-08-12 pass
6 u4 2018-07-11 pass
2 u2 2018-06-15 pass
3 u3 2018-05-18 pass

{ print }可以完全删除,我只是将其包括在内以显示会发生什么。默认操作是如果条件为真则打印整个输入记录。)

这将按日期递减(首先是最近的日期)对您拥有的文件进行排序。该awk程序读取排序后的数据并打印出为每个用户找到的第一个条目。该seen变量是一个使用用户名作为键的关联数组/哈希。如果某个用户的值为零,则表示尚未看到该用户,因此会打印文件中的行。


你的代码和我的注释:

# get list of unique usernames from log:
( awk {print} session.log | cut -f2 -d' ' | sort | uniq ) > store.txt

# shorter equivalent:
# cut -d ' ' -f2 <session.log | sort -u >store.txt

# loop over the usernames:
for line in $(cat "store.txt")
do
    # get entries related to this user:
    grep "$line" session.log > "$line.txt"

    # echo the last entry:
    echo $(sort -k3 "$line.txt" | awk 'END{print}')

    # shorter equivalent of both of the above commands:
    # awk -v user="$line" '$2 == user { print }' session.log | sort -k3,3 | tail -n 1
done
rm -f store.txt

因此,基于 shell 循环的替代方法:

cut -d ' ' -f2 <session.log | sort -u |
while read username; do
    awk -v user="$username" '$2 == user { print }' session.log | sort -k 3,3 | tail -n 1
done

同样,上面的脚本{ print }中可能会省略awk

这仍然会为每个用户对会话日志的子集进行一次排序,这有点浪费。

按日期递减对日志进行预排序:

sort -k3,3r -o sorted.log session.log

cut -d ' ' -f2 <session.log | sort -u |
while read username; do
    awk -v user="$username" '$2 == user { print; exit }' sorted.log
done

rm sorted.log

这仍然需要我们从每个用户的顶部扫描一次日志。自然的改进是允许awk跟踪用户已经看到的内容和未看到的用户,这给了你我在顶部的答案。

相关内容