Linux 명령 "sort"를 사용하여 날짜 열을 기준으로 정렬하는 쉘 스크립트

Linux 명령 "sort"를 사용하여 날짜 열을 기준으로 정렬하는 쉘 스크립트

일부 텍스트 데이터가 포함된 session.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 합격

쉘 스크립트는 날짜 형식(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사용자가 본 것과 보지 않은 것을 추적할 수 있게 하는 것입니다. 그러면 상단에 제 답변이 표시됩니다.

관련 정보