다음 내용이 포함된 파일이 있습니다(항목이 3개 이상일 수도 있음).
A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023
unix timestamp
이제 모든 항목에서 날짜와 시간을 추출 하고 싶습니다 . 즉, 나는 2019/05/21 03:33:04
, , 2019/05/21 03:33:04
에 관심이 있다 Tue Apr 4 09:14:17 UTC 2023
. 항목은 나중에 비교할 수 있도록 동일한 형식이어야 합니다. 또한 위치는 고정되지 않습니다(그러나 행의 마지막 두 필드가 됩니다).
bash
다음은 스크립트의 일부 입니다 .
#!/bin/bash
ver_file="/home/test/tmp.txt"
ver_c=$(grep -E "C Version:" $ver_file | cut -d" " -f3-)
echo "$ver_c"
누군가 파일에서 날짜를 추출하는 방법을 말해 줄 수 있습니까?
추신: 저는 WSL2를 사용하여 Ubuntu에서 개발 중이지만 대상에서는 busybox date
.
답변1
이 설명은 실제로 질문이 아니며 다소 혼란스럽습니다. 하지만 연애는 늘 즐겁기 때문에 도움이 되었으면 좋겠습니다.
구조화되지 않은 날짜를 추출하는 방법은 소스에 따라 다릅니다. 문서의 날짜는 악명이 높습니다. 주어진 예에서 내가 볼 수 있는 유일한 일관성은 날짜 문자열이 행의 끝에 있고 모두 열 6에서 시작한다는 것입니다. 그것이 제가 가장 먼저 찾는 것입니다.
위치가 "고정"되지 않은 경우 모두 6열에서 시작하지 않는다고 가정하면 세 번째 행의 날짜도 마지막 두 열이 아닙니다. 혼란스러운 예입니다. 어쨌든 그것은 가능합니다. 다양한 유형의 날짜 문자열과 각각을 처리하는 방법을 평가하려면 더 많은 논리가 필요합니다. 다시 말하지만 이는 실제로 입력 데이터 품질(GIGO)에 따라 달라집니다.
이는 GNU bash 및 핵심 유틸리티를 통해 다양한 방식으로 수행될 수 있습니다. 강조할 주요 도구는 날짜의 유효성을 평가하고 정규화하는 GNU date 명령입니다. 이 예에서 "UTC 2023"은기술적으로GNU 날짜가 잘못되지 않도록 하는 유효한 날짜입니다(그리고 bash로 캡처해야 합니다). 하지만 이와 같은 문제는 매우 간단하고 높은 정확도로 해결될 수 있습니다.
이와 같이 모든 날짜 문자열이 열 6에서 시작하거나 유효한 날짜가 마지막 두 열에 있다고 가정합니다.
while read line; do
echo $line
DATE_SIX="$(echo $line | cut -f6- -d' ')"
if date --utc --date "${DATE_SIXE}" &> /dev/null; then
DATE_SIX_NORMAL="$(date --utc --date "${DATE_SIX}")"
DATE_SIX_EPOCH="$(date --utc --date "${DATE_SIX}" +%s)"
else
DATE_SIX_NORMAL="BAD DATE"
DATE_SIX_EPOCH=0
fi
echo "DATE_SIX='${DATE_SIX}', DATE_SIX_NORMAL='${DATE_SIX_NORMAL}', DATE_SIX_EPOCH=${DATE_SIX_EPOCH}"
DATE_LAST_TWO="$(echo $line | awk '{print $(NF-1)" "$(NF)}')"
if [[ "${DATE_LAST_TWO}" != *":"* ]] || [[ "${DATE_LAST_TWO}" != *"/"* ]]; then
# GNU date evaluates "UTC 2023" as a valid date, but it's not what's wanted ...
DATE_LAST_TWO_NORMAL="BAD DATE"
DATE_LAST_TWO_EPOCH=0
else
if date --utc --date "${DATE_LAST_TWO}" &> /dev/null; then
DATE_LAST_TWO_NORMAL="$(date --utc --date "${DATE_LAST_TWO}")"
DATE_LAST_TWO_EPOCH="$(date --utc --date "${DATE_LAST_TWO}" +%s)"
else
DATE_LAST_TWO_NORMAL="BAD DATE"
DATE_LAST_TWO_EPOCH=0
fi
fi
echo "DATE_LAST_TWO='${DATE_LAST_TWO}', DATE_LAST_TWO_NORMAL='${DATE_LAST_TWO_NORMAL}', DATE_LAST_TWO_EPOCH=${DATE_LAST_TWO_EPOCH}"
echo
done < in.tmp
그 출력은 아래와 같습니다. 물론, DATE_EPOCH는 비교를 위한 정수로 사용될 수 있습니다.
A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
DATE_SIX='2019/05/21 03:33:04', DATE_SIX_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_SIX_EPOCH=1558409584
DATE_LAST_TWO='2019/05/21 03:33:04', DATE_LAST_TWO_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_LAST_TWO_EPOCH=1558409584
B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
DATE_SIX='2019/05/21 03:33:04', DATE_SIX_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_SIX_EPOCH=1558409584
DATE_LAST_TWO='2019/05/21 03:33:04', DATE_LAST_TWO_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_LAST_TWO_EPOCH=1558409584
C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023
DATE_SIX='Tue Apr 4 09:14:17 UTC 2023', DATE_SIX_NORMAL='Tue Apr 4 09:14:17 AM UTC 2023', DATE_SIX_EPOCH=1680599657
DATE_LAST_TWO='UTC 2023', DATE_LAST_TWO_NORMAL='BAD DATE', DATE_LAST_TWO_EPOCH=0
...cut 외에도 awk, bash 문자열 작업 등과 같은 다른 방법이 있습니다.
GNU date 명령은 타임스탬프를 변환하고 정규화할 수 있습니다.
또한 시간대가 없는 원래 날짜는 UTC라고 가정합니다.
그러나 사용자 정의 시간대를 지정할 수도 있습니다(예: 날짜 앞에 TZ 사용).
예를 들어,
$ date --utc --date="2019/05/21 03:33:04"
Tue May 21 03:33:04 AM UTC 2019
$ date --utc --date="Tue Apr 4 09:14:17 UTC 2023"
Tue Apr 4 09:14:17 AM UTC 2023
또는 원시 날짜 문자열을 에포크 시간으로 변환합니다...
$ date --utc --date="2019/05/21 03:33:04" +%s
1558409584
date --utc --date="Tue Apr 4 09:14:17 UTC 2023" +%s
1680599657
...또는 man date(1) 또는 FORMAT 컨트롤의 옵션 조합을 사용합니다.
$ date --utc --date="2019/05/21 03:33:04" --rfc-email
Tue, 21 May 2019 03:33:04 +0000
$ date --utc --date="2019/05/21 03:33:04" +%Y%m%d%H%M%S
20190521033304
date --utc --date="Tue Apr 4 09:14:17 UTC 2023" +%s
1680599657
$ TZ=America/New_York date --date="Tue Apr 4 09:14:17 UTC 2023"
Tue Apr 4 05:14:17 AM EDT 2023
비교를 위해 나는 unix epoch 타임스탬프를 선호합니다.
답변2
첫 번째 값에 대한 시간대를 정의하지 않았으므로 전 세계 어디에 있든 "현지 시간"이라고 가정합니다.
저는 여기에서 GNU를 사용 grep
했습니다 date
:
grep -oE '..../../.. ..:..:..$|... [[:digit:]]+ ..:..:.. [[:alnum:]]+ ....$' datafile |
while IFS= read date
do
esec=$(date --date "$date" +%s)
printf "%s --> %d\n" "$date" "$esec"
done
예제 데이터의 경우 내(UK - GMT/BST) 시간대에서 실행할 때의 출력은 다음과 같습니다. GMT/BST 또는 이에 상응하는 WET 시간대에 있지 않는 한 초 값은 달라집니다.
2019/05/21 03:33:04 --> 1558405984
2019/05/21 03:33:04 --> 1558405984
Apr 4 09:14:17 UTC 2023 --> 1680599657
답변3
이 날짜는 perl로 쉽게 구문 분석됩니다 Date::Parse
.
Unix epoch 시간을 앞에 추가하려면(숫자 비교 가능):
perl -MDate::Parse -pe '
$_ = str2time(m{( 20\d\d/\d\d.*|\S+ \S+ \d+ \S+ UTC 20\d\d$)}) . " $_"
' < your-file
이것은 만든다:
1558409584 A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
1558409584 B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
1680599657 C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023
또는 ISO8601 스타일 시간 형식의 경우(어휘 비교 가능):
perl -MDate::Parse -MPOSIX -pe '
$_ = strftime("%FT%T", strptime m{(20\d\d/\d\d.*|\S+ \S+ \d+ \S+ UTC 20\d\d$)}) . " $_"
' < your-file
이것은 만든다:
2019-05-21T02:33:04 A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
2019-05-21T02:33:04 B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
2023-04-04T09:14:17 C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023