कैसे दो समय टिकटों के बीच लॉग निकालने के लिए


25

मैं दो टाइमस्टैम्प के बीच सभी लॉग निकालना चाहता हूं। कुछ पंक्तियों में टाइमस्टैम्प नहीं हो सकता है, लेकिन मैं उन पंक्तियों को भी चाहता हूं। संक्षेप में, मैं हर उस लाइन को चाहता हूं जो दो टाइम स्टैम्प के अंतर्गत आती है। मेरी लॉग संरचना इस प्रकार है:

[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

कृपया ध्यान दें कि स्टार्ट टाइम स्टैम्प या अंत समय स्टैम्प लॉग में नहीं हो सकता है, लेकिन मैं इन दो समय टिकटों के बीच की हर लाइन चाहता हूं।


के संभावित डुप्लिकेट stackoverflow.com/questions/7575267/...
रमेश

क्या आपको सिर्फ एक बार या प्रोग्रामिक रूप से कई बार ऐसा करने की जरूरत है?
ब्राचली

कारण मैं पूछ रहा हूं क्योंकि आप दो प्रासंगिक grep कर सकते हैं (एक प्रारंभिक सीमांकक के बाद सब कुछ हड़पने के लिए और दूसरा समाप्त सीमांकक पर मुद्रण बंद करने के लिए) यदि आप शाब्दिक मूल्यों को जानते हैं। यदि दिनांक / समय बदल सकते हैं, तो टाउ आसानी से date -dकमांड के माध्यम से उपयोगकर्ता इनपुट खिलाकर और खोज पैटर्न का निर्माण करने के लिए इसका उपयोग करके मक्खी पर उत्पन्न कर सकता है ।
ब्राचली

@ रमेश, संदर्भित प्रश्न बहुत व्यापक है।
मैक्सक्लेपज़िग

@JoelDavis: मैं इसे प्रोग्रामेटिक रूप से करना चाहता हूं। इसलिए हर बार मुझे केवल मेरे / tmp स्थान में उन समय टिकटों के बीच लॉग निकालने के लिए वांछित समय टिकट दर्ज करने की आवश्यकता होती है।
अमित

जवाबों:


19

आप इसके लिए उपयोग कर सकते हैं 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/ सच है अगर रेगेक्स मेल खाता है $0
  • >=lexicographically तुलना स्ट्रिंग (उदाहरण के बराबर 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

(ध्यान दें कि फ़ील्ड विभाजक भी बदल गया है - रिक्त / गैर-रिक्त संक्रमण के लिए, डिफ़ॉल्ट)


स्क्रिप्ट साझा करने के लिए थैंक्स, लेकिन इसकी टाइमस्टैम्प की जाँच नहीं है .. क्या आप कृपया जाँच कर सकते हैं। मुझे यह भी बताएं कि अगर मेरे पास 2014-04-07 23:59:58 जैसे लॉग हैं तो क्या होगा। मेरा मतलब है बिना ब्रेसिज़ के
अमित

@Amit, जवाब अपडेट किया
maxschlepzig

हालांकि मुझे नहीं लगता कि यह एक स्ट्रिंग समस्या है ( मेरा उत्तर देखें ), आप सभी परीक्षणों को दोहरा नहीं कर सकते हैं, और संभवत: थोड़ा और तेज कर सकते हैं: $1 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}/ && $2 ~/[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/ { Time = $1" "$2; if (Time >= "2014-04-07 23:00" ) { p=1 } if (Time >= "2014-04-08 02:00:01" ) { p=0 } } p

हाय मैक्स, एक और छोटी सी शंका .. अगर मेरे पास Apr-07-2014 10:51:17 जैसा कुछ है। फिर मुझे क्या परिवर्तन करने की आवश्यकता है .. मैंने code$ 0 ~ / ^ [az | AZ] {4} - [0-9] {2} - [0-9] {4} [0-2] [0-9 की कोशिश की ]: [०-५] [०- ९]: [०-५] [०- ९] / && $ १ "" "$ २> =" अप्रैल-० >-२०१४ ११:०० "{p = १} $ ० ~ / ^ [az | AZ] {4} - [0-9] {2} - [0-9] {4} [0-2] [0-9]: [0-5] [0-9]: [0 -5] [0-9] / && $ 1 "" $ 2> = "अप्रैल-07-2014 00:00:01" {पी = 0} codeलेकिन इसके काम नहीं कर रहा
अमित

@awk_FTW, कोड को ऐसे बदला कि रेगेक्स स्पष्ट रूप से साझा हो।
मैक्सचेलपिजिग

12

की जाँच करें dategrepपर https://github.com/mdom/dategrep

विवरण:

dategrep एक तिथि सीमा से मेल खाती लाइनों के लिए नामित इनपुट फ़ाइलों को खोजता है और उन्हें stdout में प्रिंट करता है।

यदि dategrep एक खोजी फ़ाइल पर काम करता है, तो यह सुंदर ढंग से मुद्रित करने के लिए पहली और आखिरी पंक्ति को खोजने के लिए एक द्विआधारी खोज कर सकता है। अगर फ़ाइल नाम के तर्क सिर्फ एक हाइफ़न है, तो स्टड से dategrep भी पढ़ा जा सकता है, लेकिन इस मामले में उसे हर एक पंक्ति को पार्स करना होगा, जो धीमी होगी।

उपयोग के उदाहरण:

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" -

यद्यपि यह सीमा आपके सटीक प्रश्न के लिए इसे अनुपयुक्त बना सकती है:

इस समय जैसे ही यह रेखा पारगम्य नहीं होगी, मर जाएगा। भविष्य के संस्करण में यह कॉन्फ़िगर करने योग्य होगा।


मैंने इस आदेश के बारे में कुछ दिनों पहले ही सीखा था, जब शिष्टाचार का आगमन हो रहा था।
cpugeniusmv

3

awkया गैर-मानक उपकरण के लिए एक विकल्प है कि वह grepअपने संदर्भीय greps के लिए 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 लाइनों के साथ लाइन को प्रिंट करने के लिए कहता है। इन दोनों का अंतिम परिणाम शुरू हो रहा है, जहाँ आप चाहते हैं और जहाँ आप इसे रोकने के लिए कहा था वहाँ नहीं जा रहे हैं।

१०,००० सिर्फ एक संख्या है जिसके साथ मैं आया था, इसे एक मिलियन में बदलने के लिए स्वतंत्र महसूस करें यदि आपको लगता है कि आपका आउटपुट बहुत लंबा होने वाला है।


यदि प्रारंभ और अंत श्रेणियों के लिए कोई लॉग प्रविष्टि नहीं है, तो यह कैसे काम करने वाला है? यदि ओपी 14:00 और 15:00 के बीच सब कुछ चाहता है, लेकिन 14:00 के लिए कोई लॉग प्रविष्टि नहीं है, तो?

यह शब्द के साथ ही sedशाब्दिक मैचों के लिए भी खोज कर रहा है। dategrepसंभवतः सभी दिए गए लोगों का सबसे सही उत्तर है (क्योंकि आपको जो टाइमस्टैम्प स्वीकार करना होगा उस पर "फजी" होने में सक्षम होने की आवश्यकता है) लेकिन जैसे उत्तर कहता है, मैं सिर्फ एक विकल्प के रूप में इसका उल्लेख कर रहा था। कहा कि, यदि लॉग वारंट के लिए पर्याप्त उत्पादन उत्पन्न करने के लिए पर्याप्त सक्रिय है, तो यह संभवतः दिए गए गेरोइड के लिए किसी प्रकार का प्रवेश करने जा रहा है ।
ब्राचली

0

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"

इसे एक फाइल में कॉपी करें। यदि आप डिबगिंग जानकारी नहीं देखना चाहते हैं, तो डिबगिंग को स्टेदर पर भेजा जाता है, इसलिए "2> / dev / null जोड़ें"


1
यह अभ्यस्त लॉग फ़ाइलों को प्रदर्शित करता है, जिसमें समय की मुहर नहीं होती है।
अमित

@ अमित, हाँ, यह तुमने कोशिश की होगी?
UnX

@rMistero, यह काम नहीं करेगा क्योंकि अगर 22:30 पर कोई लॉग प्रविष्टि नहीं है, तो सीमा समाप्त नहीं होगी। जैसा कि ओपी ने उल्लेख किया है, प्रारंभ और रोक समय लॉग में नहीं हो सकता है। यह काम करने के लिए आप अपने रेगुलर एक्सप्रेशन से ठीक कर सकते हैं, लेकिन आप संकल्प ढीला हूँ और कभी नहीं की गारंटी दी जा अग्रिम में है कि सीमा सही समय पर समाप्त होगा।

@awk_FTW यह एक उदाहरण था, मैंने अमित द्वारा प्रदान की गई टाइमस्टैम्प का उपयोग नहीं किया। फिर से रेगेक्स का उपयोग किया जा सकता है। मुझे लगता है कि यह काम नहीं करेगा अगर टाइमस्टैम्प मौजूद नहीं है या जब कोई टाइमस्टैम्प रेगेक्स मैच नहीं करता है। मैं जल्द ही इसमें सुधार
करूंगा

"जैसा कि ओपी ने उल्लेख किया है, प्रारंभ और रोक समय लॉग में नहीं हो सकता है।" नहीं, ओपी को फिर से पढ़ें। ओपी कहते हैं कि वे मौजूद होंगे लेकिन हस्तक्षेप करने वाली लाइनें जरूरी नहीं कि टाइमस्टैम्प से शुरू हों। यह कहने का भी मतलब नहीं है कि स्टॉप बार मौजूद नहीं हो सकता है। आप कभी भी किसी भी उपकरण को कैसे बता सकते हैं जहां रोकना है अगर समाप्ति मार्कर वहां होने की गारंटी नहीं है? प्रसंस्करण को रोकने के लिए यह बताने के लिए उपकरण देने के लिए कोई मापदंड नहीं होगा।
ब्राचली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.