Linuxコマンド「sort」を使用して日付列に基づいてソートするシェルスクリプト

Linuxコマンド「sort」を使用して日付列に基づいてソートするシェルスクリプト

一部のテキストデータを含むsession.logというファイルがあります。最初の列にはシリアル番号が含まれています。 2 番目の列にはユーザー名が含まれます。 3 番目の列には最後のログイン日が含まれます。 4番目の列には結果が含まれます。

ユーザーが複数回ログインします。各一意のユーザーの最後のログイン日を見つける必要があります。だからシェルスクリプトを書いた。出力には、各固有ユーザー(2番目の列)の最新のログイン日(3番目の列)を持つ行が表示されます。出力には同じユーザー名を複数回含めないでください。

$猫セッション。ログ
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 合格

シェルスクリプトは日付形式(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 }完全に削除できます。何が起こるかを示すために含めただけです。デフォルトの動作は、条件がtrueの場合は入力レコード全体を印刷することです。)

これにより、保存したファイルが日付順に降順(最も最近のエントリから)にソートされます。プログラムawkはソートされたデータを読み取り、ユーザーごとに見つかった最初の項目を印刷します。変数seenは、ユーザー名をキーとして使用する連想配列/ハッシュです。ユーザー値が 0 の場合、そのユーザーはまだ確認されていないことを意味するため、ファイル内の対応する行が印刷されます。


あなたのコードと私のコメント:

# 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

したがって、シェルルーピングに基づく代替は次のとおりです。

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あなたが見たものと見たことのないものを追跡できるようにすることです。これにより、上部に私の答えが表示されます。

関連情報