두 타임 스탬프 사이의 모든 로그를 추출하고 싶습니다. 일부 라인에는 타임 스탬프가 없을 수도 있지만 해당 라인도 원합니다. 요컨대, 두 개의 타임 스탬프에 해당하는 모든 라인을 원합니다. 내 로그 구조는 다음과 같습니다.
[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall
2014-04-07 23:00
와 사이의 모든 것을 추출하고 싶다고 가정 해보십시오 2014-04-08 02:00
.
시작 타임 스탬프 또는 종료 타임 스탬프가 로그에 없을 수 있지만이 두 타임 스탬프 사이의 모든 줄을 원합니다.
답변
awk
이것을 위해 사용할 수 있습니다 :
$ awk -F'[]]|[[]' \
'$0 ~ /^\[/ && $2 >= "2014-04-07 23:00" { p=1 }
$0 ~ /^\[/ && $2 >= "2014-04-08 02:00" { p=0 }
p { print $0 }' log
어디에:
-F
정규식을 사용하여 문자[
와]
필드 구분 기호를 지정합니다.$0
완전한 라인을 참조$2
날짜 필드를 참조p
실제 인쇄를 보호하는 부울 변수로 사용됩니다.$0 ~ /regex/
정규식이 일치하면 true$0
>=
문자열을 사전 식으로 비교하는 데 사용됩니다 (예 :와 동일strcmp()
)
변형
위의 명령 줄은 오른쪽 열림 시간 간격 일치를 구현 합니다. 닫힌 간격 의미를 얻으려면 올바른 날짜를 늘리십시오. 예 :
$ awk -F'[]]|[[]' \
'$0 ~ /^\[/ && $2 >= "2014-04-07 23:00" { p=1 }
$0 ~ /^\[/ && $2 >= "2014-04-08 02:00:01" { p=0 }
p { print $0 }' log
다른 형식으로 타임 스탬프를 일치 시키려면 $0 ~ /^\[/
하위 표현식 을 수정해야합니다 . 인쇄 켜짐 / 꺼짐 논리에서 타임 스탬프가없는 행을 무시하는 데 사용되었습니다.
예를 들어 중괄호 YYYY-MM-DD HH24:MI:SS
없이 타임 스탬프 형식의 경우 다음과 같이 []
명령을 수정할 수 있습니다.
$ awk \
'$0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/
{
if ($1" "$2 >= "2014-04-07 23:00") p=1;
if ($1" "$2 >= "2014-04-08 02:00:01") p=0;
}
p { print $0 }' log
(필드 구분 기호도 변경됨-기본값은 공백 / 비 공백으로 변경됨)
답변
https://github.com/mdom/dategrepdategrep
에서 확인 하십시오
기술:
dategrep은 명명 된 입력 파일에서 날짜 범위와 일치하는 행을 검색하여 stdout에 인쇄합니다.
dategrep이 검색 가능한 파일에서 작동하는 경우 바이너리 검색을 수행하여 첫 번째 및 마지막 줄을 찾아 매우 효율적으로 인쇄 할 수 있습니다. 파일 이름 인수 중 하나가 하이픈 인 경우 dategrep을 stdin에서 읽을 수도 있지만이 경우 느린 모든 줄을 구문 분석해야합니다.
사용 예 :
dategrep --start "12:00" --end "12:15" --format "%b %d %H:%M:%S" syslog
dategrep --end "12:15" --format "%b %d %H:%M:%S" syslog
dategrep --last-minutes 5 --format "%b %d %H:%M:%S" syslog
dategrep --last-minutes 5 --format rsyslog syslog
cat syslog | dategrep --end "12:15" -
이 제한으로 인해 정확한 질문에 적합하지 않을 수 있습니다.
현재 dategrep은 구문 분석 할 수없는 줄을 찾으면 죽을 것입니다. 향후 버전에서는이를 구성 할 수 있습니다.
답변
awk
비표준 도구의 대안 또는 비표준 도구는 grep
상황에 맞는 grep에 GNU를 사용하는 것입니다. GNU grep
에서는 양의 일치 후 인쇄 할 -A
행 수와 이전 행을 인쇄 할 행 수를 지정할 수 있습니다. -B
예를 들면 다음 과 같습니다.
[davisja5@xxxxxxlp01 ~]$ cat test.txt
Ignore this line, please.
This one too while you're at it...
[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall
we don't
want these lines.
[davisja5@xxxxxxlp01 ~]$ egrep "^\[2014-04-07 23:59:58\]" test.txt -A 10000 | egrep "^\[2014-04-08 00:00:03\]" -B 10000
[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall
위의 내용은 기본적으로 grep
원하는 패턴과 일치하는 줄을 따르는 10,000 줄을 인쇄하여 출력을 원하는 곳에서 시작하고 끝까지 (희망스럽게) 끝까지 가도록 egrep
합니다. 파이프 라인은 끝 구분 기호가있는 행과 그 앞에 10,000 행만 인쇄하도록 지시합니다. 이 두 가지의 최종 결과는 당신이 원하는 곳에서 시작하고 멈추라 고 말한 곳에서지나 가지 않습니다.
10,000은 내가 생각 해낸 숫자이므로 출력이 너무 길다고 생각되면 자유롭게 백만으로 변경하십시오.
답변
sed 사용 :
#!/bin/bash
E_BADARGS=23
if [ $# -ne "3" ]
then
echo "Usage: `basename $0` \"<start_date>\" \"<end_date>\" file"
echo "NOTE:Make sure to put dates in between double quotes"
exit $E_BADARGS
fi
isDatePresent(){
#check if given date exists in file.
local date=$1
local file=$2
grep -q "$date" "$file"
return $?
}
convertToEpoch(){
#converts to epoch time
local _date=$1
local epoch_date=`date --date="$_date" +%s`
echo $epoch_date
}
convertFromEpoch(){
#converts to date/time format from epoch
local epoch_date=$1
local _date=`date --date="@$epoch_date" +"%F %T"`
echo $_date
}
getDates(){
# collects all dates at beginning of lines in a file, converts them to epoch and returns a sequence of numbers
local file="$1"
local state="$2"
local i=0
local date_array=( )
if [[ "$state" -eq "S" ]];then
datelist=`cat "$file" | sed -r -e "s/^\[([^\[]+)\].*/\1/" | egrep "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"`
elif [[ "$state" -eq "E" ]];then
datelist=`tac "$file" | sed -r -e "s/^\[([^\[]+)\].*/\1/" | egrep "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"`
else
echo "Something went wrong while getting dates..." 1>&2
exit 500
fi
while read _date
do
epoch_date=`convertToEpoch "$_date"`
date_array[$i]=$epoch_date
#echo "$_date" "$epoch_date" 1>&2
(( i++ ))
done<<<"$datelist"
echo ${date_array[@]}
}
findneighbours(){
# search next best date if date is not in the file using recursivity
IFS="$old_IFS"
local elt=$1
shift
local state="$1"
shift
local -a array=( "$@" )
index_pivot=`expr ${#array[@]} / 2`
echo "#array="${#array[@]} ";array="${array[@]} ";index_pivot="$index_pivot 1>&2
if [ "$index_pivot" -eq 1 -a ${#array[@]} -eq 2 ];then
if [ "$state" == "E" ];then
echo ${array[0]}
elif [ "$state" == "S" ];then
echo ${array[(( ${#array[@]} - 1 ))]}
else
echo "State" $state "undefined" 1>&2
exit 100
fi
else
echo "elt with index_pivot="$index_pivot":"${array[$index_pivot]} 1>&2
if [ $elt -lt ${array[$index_pivot]} ];then
echo "elt is smaller than pivot" 1>&2
array=( ${array[@]:0:(($index_pivot + 1)) } )
else
echo "elt is bigger than pivot" 1>&2
array=( ${array[@]:$index_pivot:(( ${#array[@]} - 1 ))} )
fi
findneighbours "$elt" "$state" "${array[@]}"
fi
}
findFirstDate(){
local file="$1"
echo "Looking for first date in file" 1>&2
while read line
do
echo "$line" | egrep -q "^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\]" &>/dev/null
if [ "$?" -eq "0" ]
then
#echo "line=" "$line" 1>&2
firstdate=`echo "$line" | sed -r -e "s/^\[([^\[]+)\].*/\1/"`
echo "$firstdate"
break
else
echo $? 1>&2
fi
done< <( cat "$file" )
}
findLastDate(){
local file="$1"
echo "Looking for last date in file" 1>&2
while read line
do
echo "$line" | egrep -q "^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\]" &>/dev/null
if [ "$?" -eq "0" ]
then
#echo "line=" "$line" 1>&2
lastdate=`echo "$line" | sed -r -e "s/^\[([^\[]+)\].*/\1/"`
echo "$lastdate"
break
else
echo $? 1>&2
fi
done< <( tac "$file" )
}
findBestDate(){
IFS="$old_IFS"
local initdate="$1"
local file="$2"
local state="$3"
local first_elts="$4"
local last_elts="$5"
local date_array=( )
local initdate_epoch=`convertToEpoch "$initdate"`
if [[ $initdate_epoch -lt $first_elt ]];then
echo `convertFromEpoch "$first_elt"`
elif [[ $initdate_epoch -gt $last_elt ]];then
echo `convertFromEpoch "$last_elt"`
else
date_array=( `getDates "$file" "$state"` )
echo "date_array="${date_array[@]} 1>&2
#first_elt=${date_array[0]}
#last_elt=${date_array[(( ${#date_array[@]} - 1 ))]}
echo `convertFromEpoch $(findneighbours "$initdate_epoch" "$state" "${date_array[@]}")`
fi
}
main(){
init_date_start="$1"
init_date_end="$2"
filename="$3"
echo "problem start.." 1>&2
date_array=( "$init_date_start","$init_date_end" )
flag_array=( 0 0 )
i=0
#echo "$IFS" | cat -vte
old_IFS="$IFS"
#changing separator to avoid whitespace issue in date/time format
IFS=,
for _date in ${date_array[@]}
do
#IFS="$old_IFS"
#echo "$IFS" | cat -vte
if isDatePresent "$_date" "$filename";then
if [ "$i" -eq 0 ];then
echo "Starting date exists" 1>&2
#echo "date_start=""$_date" 1>&2
date_start="$_date"
else
echo "Ending date exists" 1>&2
#echo "date_end=""$_date" 1>&2
date_end="$_date"
fi
else
if [ "$i" -eq 0 ];then
echo "start date $_date not found" 1>&2
else
echo "end date $_date not found" 1>&2
fi
flag_array[$i]=1
fi
#IFS=,
(( i++ ))
done
IFS="$old_IFS"
if [ ${flag_array[0]} -eq 1 -o ${flag_array[1]} -eq 1 ];then
first_elt=`convertToEpoch "$(findFirstDate "$filename")"`
last_elt=`convertToEpoch "$(findLastDate "$filename")"`
border_dates_array=( "$first_elt","$last_elt" )
#echo "first_elt=" $first_elt "last_elt=" $last_elt 1>&2
i=0
IFS=,
for _date in ${date_array[@]}
do
if [ $i -eq 0 -a ${flag_array[$i]} -eq 1 ];then
date_start=`findBestDate "$_date" "$filename" "S" "${border_dates_array[@]}"`
elif [ $i -eq 1 -a ${flag_array[$i]} -eq 1 ];then
date_end=`findBestDate "$_date" "$filename" "E" "${border_dates_array[@]}"`
fi
(( i++ ))
done
fi
sed -r -n "/^\[${date_start}\]/,/^\[${date_end}\]/p" "$filename"
}
main "$1" "$2" "$3"
이것을 파일로 복사하십시오. 디버깅 정보를 보지 않으려면 디버깅이 stderr로 전송되므로 “2> / dev / null”을 추가하십시오.