Entra

View Full Version : [UNIX] Script shell - come estrarre due valori su due righe diverse da un file di log


pumapc
08-05-2014, 14:28
Ciao a tutti,

vi scrivo in quanto ho bisogno di un aiuto su come estrapolare delle informazioni da un file di log con comandi unix o con uno script Shell.

Io vorrei estrapolare da un file di log il tempo che ci impiega la query cioè grep "exec time: " ma al tempo stesso filtrare anche in base all'ora, poi con un cut -d " " -f(x) prenderei il valore dell'esecuzione della query..

Il problema è che si trovano su due righe diverse (una sopra e l'altra sotto)

2014-05-08 15:09:09,692 DEBUG - localhost -
[UID=] - exec time: 1 ms - sql statement: <QUERY ESEGUITA..............> -- result: 0 -- debug connection: 11111111

e quindi il comando:
grep " - exec time:" file.log | grep "$( date "+%Y-%m-%d %H" )" | cut -d " " -f5

non mi darebbe dei risultati soddisfacenti.

Avete per caso qualche soluzione al mio caso?

Grazie mille in anticipo.

Daniels118
14-05-2014, 13:19
Vedi se la tua versione di grep supporta l'opzione -A che ti consente di stampare un certo numero di righe successive a quella dove si trova la corrispondenza:
grep -A 1 "$( date "+%Y-%m-%d %H" )" file.log

Se poi vuoi unire le due righe puoi usare xargs:
grep -A 1 "$( date "+%Y-%m-%d %H" )" file.log | xargs -L 2 echo

e infine usi cut per selezionare le colonne che ti interessano.

pumapc
29-05-2014, 17:10
Vedi se la tua versione di grep supporta l'opzione -A che ti consente di stampare un certo numero di righe successive a quella dove si trova la corrispondenza:
grep -A 1 "$( date "+%Y-%m-%d %H" )" file.log

Se poi vuoi unire le due righe puoi usare xargs:
grep -A 1 "$( date "+%Y-%m-%d %H" )" file.log | xargs -L 2 echo

e infine usi cut per selezionare le colonne che ti interessano.

Ciao Daniels118,
grazie mille per l'aiuto..

Allora...ho provato a fare come mi hai detto ma non riesco ad unire le due righe.

Il grep con il -A1 funziona correttamente ma poi il comando xargs non me li unisce.

Ho provato ad usare questo comando:

grep -A1 " WARN - " file.log | xargs -L 2 echo

Dov'è che sbaglio?

Grazie in anticipo.

Daniels118
29-05-2014, 17:39
Cosa succede esattamente? Viene generato un errore oppure ottieni un risultato diverso?
Verifica che la tua versione di xargs supporti l'opzione -L, altrimenti possiamo utilizzare un comando diverso.

pumapc
30-05-2014, 09:18
No nessun errore....Ottengo però un risultato diverso...Cioè il comando non unisce le due righe che vorrei unire...

La versione di xargs è questa:

xargs --version
xargs (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.

e facendo un man xargs l'opzione -L risulta essere presente.

Daniels118
30-05-2014, 11:06
Puoi fornirmi 3/4 righe del file che vorresti elaborare? (ovviamente contenenti le righe che vuoi estrarre)

pumapc
30-05-2014, 12:52
Puoi fornirmi 3/4 righe del file che vorresti elaborare? (ovviamente contenenti le righe che vuoi estrarre)

Tipo così:

2014-05-30 05:00:01,166 WARN - localhost - Task - [machine#Scheduler-00011]
[ID=] - exec time: 1053 ms - sql statement: SELECT * FROM ( SELECT...............

Ovviamente non tutte le righe sono a WARN ma sono presenti anche a DEBUG e quindi con un grep -A1 prendo le due righe che mi interessano...

La prima riga ha la data e la seconda riga il tempo di esecuzione con la query loggata

Daniels118
30-05-2014, 13:17
Mea culpa, ho dimenticato che l'opzione -A fa in modo che il grep inserisca nell'output delle linee contenenti "--" per separare i risultati, per cui bisogna eliminarli prima di passare l'output ad xargs:
grep -A1 " WARN - " file.log | grep -v "^--$" | xargs -L 2 echo

pumapc
30-05-2014, 14:35
Figurati...ci mancherebbe altro.. ;)

Ho provato ad eseguire il nuovo comando ma purtroppo questa volta non mi esce nulla...cioè il risultato è una riga vuota:

[user@machine script]$ grep -A1 " WARN - " filelog.log | grep -v "^--$" | xargs -L 2 echo

[user@machine script]$

Daniels118
30-05-2014, 14:42
Il nome del file è corretto?

Verifica che ogni comando produca l'ouput previsto:

Il primo grep deve produrre una cosa del genere:
bla bla WARN - bla bla
tsk tsk
--
bla bla WARN - bla bla
tsk tsk

Il secondo grep:
bla bla WARN - bla bla
tsk tsk
bla bla WARN - bla bla
tsk tsk

E xargs:
bla bla WARN - bla bla tsk tsk
bla bla WARN - bla bla tsk tsk

Se il problema è su xargs possiamo sostituirlo con un comando tra awk, sed e paste opportunamente parametrizzati.

pumapc
30-05-2014, 15:02
Sorry...mancava uno spazio dopo il WARN che mi ha fregato nel copa e incolla e non me ne ero accorto... :-D

Ho però ancora un errore che infatti mi ritorna 2 risultati in meno rispetto a quello dovrei ricevere:

grep -A1 " WARN - " file.log | grep -v "^--$" | xargs -L 2 echo | cut -d":" -f4
1202 ms - sql statement
1053 ms - sql statement
1627 ms - sql statement
2140 ms - sql statement
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
1249 ms - sql statement
1192 ms - sql statement
1967 ms - sql statement

Parlando di awk e guardando su internet ho trovato questo comando awk 'ORS=NR%2?";":"\n"' e adattandolo al mio comando mi ritorna tutte le righe interessate:

grep -A1 " WARN - " file.log | grep -v "^--$" | awk 'ORS=NR%2?";":"\n"' | cut -d":" -f4
1202 ms - sql statement
1053 ms - sql statement
1627 ms - sql statement
2140 ms - sql statement
1249 ms - sql statement
1192 ms - sql statement
1967 ms - sql statement
1732 ms - sql statement
1031 ms - sql statement

E' corretto?

Però non ho capito bene cosa fa il comando di awk...Sono ancora poco esperto in materia di comandi complesi di unix..:(

Daniels118
30-05-2014, 15:14
Evidentemente nelle righe che hai estratto vi sono degli apici non chiusi che danno fastidio ad xargs, in effetti è meglio utilizzare altri comandi (anche se sembrano più complessi).

Il comando awk serve proprio per la manipolazione delle stringhe, in particolare quello utilizzato da te non fa altro che impostare il separatore dei record in output secondo questo criterio:

punto e virgola se il numero di riga è pari
a capo se il numero di riga è dispari

i numeri di riga partono da 1.
In tal modo le righe verranno concatenate una volta con il punto e virgola e una volta con a capo, generando righe concatenate due a due.

pumapc
10-06-2014, 11:22
Ciao Daniels,

grazie mille per il grande aiuto e per tutte le info!!

Mi rivedrò un pò come funziona l'AWK perchè ho capito in generale come funziona ma faccio ancora fatica a capire i vari paramtri inseriti all'interno dell'AWK... :D

Daniels118
10-06-2014, 11:50
Ciao Daniels,

grazie mille per il grande aiuto e per tutte le info!!

Mi rivedrò un pò come funziona l'AWK perchè ho capito in generale come funziona ma faccio ancora fatica a capire i vari paramtri inseriti all'interno dell'AWK... :D
Figurati... :)
Comunque i parametri fanno questo:
ORS significa "Output Record Separator", quindi "ORS=bla" imposta il separatore dei record di output a "bla".
NR sta per Numero di Riga.
L'espressione "A % B" divide A per B e restituisce il resto della divisione.
L'operazione "NR%2" quindi vale 0 per le righe pari e 1 per quelle dispari.
L'espressione "cond ? A : B" vale "A" se "cond" è vera, "B" in caso contrario; il valore zero viene interpretato come false, qualunque altro valore come vero.
L'espressione 'NR%2?";":"\n"' vale quindi ";" per le righe dispari e "\n" per le righe pari.
Poiché le righe pari e quelle dispari vengono una si e una no, ne conseguirà che i record di input verranno concatenati due a due.

pumapc
23-06-2014, 10:04
Figurati... :)
Comunque i parametri fatto questo:
ORS significa "Output Record Separator", quindi "ORS=bla" imposta il separatore dei record di output a "bla".
NR sta per Numero di Riga.
L'espressione "A % B" divide A per B e restituisce il resto della divisione.
L'operazione "NR%2" quindi vale 0 per le righe pari e 1 per quelle dispari.
L'espressione "cond ? A : B" vale "A" se "cond" è vera, "B" in caso contrario; il valore zero viene interpretato come false, qualunque altro valore come vero.
L'espressione 'NR%2?";":"\n"' vale quindi ":" per le righe pari e "\n" per le righe dispari.
Poiché le righe pari e quelle dispari vengono una si e una no, ne conseguirà che i record di input verranno concatenati due a due.


Ciao Daniels,

fantastico...grazie mille per la spiegazione molto accurata..
Ora mi ètutto un pò più chiaro anche se devo farci un pò di pratica e fare qualche esempio per capire meglio l'awk.

Una cosa e il parametro ";" a cosa servirebbe? per dividere le due righe concatenate una dal ":" e l'altra dallo "\n" ?

Daniels118
23-06-2014, 10:24
Scusami, nel precedente messaggio ho commesso un errore di battitura scrivendo i due punti al posto del punto e virgola, l'affermazione corretta è questa:
L'espressione 'NR%2?";":"\n"' vale quindi ";" per le righe dispari e "\n" per le righe pari.
La tua domanda diventerebbe quindi:
Una cosa e il parametro ":" a cosa servirebbe? per dividere le due righe concatenate una dal ";" e l'altra dallo "\n" ?
Più che dividere in questo caso bisognerebbe dire unire, infatti noi non vogliamo separare le righe ma unirle due a due e il ";" è il carattere con cui le uniamo (potremmo anche mettere semplicemente "", ma poi non sarebbe più possibile capire dove finiva la riga precedente e dove cominciava la successiva). Anche nel caso del "\n" le stiamo unendo, solo che tale carattere è proprio il separatore di riga, pertanto le righe resteranno divise, se preferisci puoi dire che le stai unendo con un divisore :)
Comunque il termine corretto non è "parametro" ma "operatore", infatti i simboli "?:" nel costrutto
espressione_booleana ? espressione1 : espressione2
prendono il nome di "operatore condizionale".

pumapc
23-06-2014, 10:37
Scusami, nel precedente messaggio ho commesso un errore di battitura scrivendo i due punti al posto del punto e virgola, l'affermazione corretta è questa:

La tua domanda diventerebbe quindi:

Più che dividere in questo caso bisognerebbe dire unire, infatti noi non vogliamo separare le righe ma unirle due a due e il ";" è il carattere con cui le uniamo (potremmo anche mettere semplicemente "", ma poi non sarebbe più possibile capire dove finiva la riga precedente e dove cominciava la successiva). Anche nel caso del "\n" le stiamo unendo, solo che tale carattere è proprio il separatore di riga, pertanto le righe resteranno divise, se preferisci puoi dire che le stai unendo con un divisore :)
Comunque il termine corretto non è "parametro" ma "operatore", infatti i simboli "?:" nel costrutto
espressione_booleana ? espressione1 : espressione2
prendono il nome di "operatore condizionale".

Figurati ci mancherebbe altro... ;) Anzi grazie mille per la notevole spiegazione e pazienza :-D

Si in effetti meglio chiamare operatore che parametro...:D

Grazie mille di tutto..