일부 텍스트 데이터가 포함된 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
사용자가 본 것과 보지 않은 것을 추적할 수 있게 하는 것입니다. 그러면 상단에 제 답변이 표시됩니다.