martedì 28 gennaio 2020

TAIL in BATCH - windows come linux

Buongiorno a tutti e benvenuti ad un altro post del mio blog : "lo Scriptomane".

Oggi parleremo di come ottenere, con uno script, un funzionamento molto simile a quello del comando tail di Linux/Unix anche sui nostri amati host windows.

Lo script: TAIL.BAT 

ed eccolo qui, in tutta la sua semplice bellezza:


@ECHO OFF REM tail.bat REM Implementazione di un comando TAIL in windows batch di Diego Castelli. Setlocal EnableDelayedExpansion for /f "usebackq delims=: tokens=1,2,*" %%f in (`find /c /v "" %1 ^|FINDSTR /R /C:":[\s]*[0-9]*"`) do ( REM echo f: %%f g: %%g h: %%h set /A fileLines=%%g set /A Lns=%2 set /A Lns2Skip=!fileLines!-!Lns! more "%1" +!Lns2Skip! REM for /f "usebackq skip=%Lns2Skip% delims=" %%d in (%1) do echo %%d )













Devo dire che, prima di esplorare a fondo le caratteristiche del comando FOR di batch, tail era uno strumento che sognavo di usare nei miei scripts… mi faceva una grande invidia quando lo utilizzavo dalla riga di comando o in uno script bash.

Piano piano, vedendo le opzioni di FOR, si è insinuata l’idea di poterlo realizzare anche in batch in modo semplice, per espandere le capacità degli script e raggiungere nuovi livelli di automazione…
Ecco quindi la spiegazione, step by step di come si comporta lo script:

prepariamo l’ambiente

Salterò “i convenevoli” e non parlerò di echo off e setLocal EnableDelayedExpansion. Se volete approfondire vi invito a leggere un altro post del mio blog:

il mitico FOR

Qui sotto copio e incollo le spiegazioni dell’help del comando for, per dettagliare cosa fa ogni cosa:
con l’opzione /f "usebackq delims=: tokens=1,2,*" andiamo a dire a FOR:

/f : usa le opzioni estese che verranno specificate tra virgolette

Usebackq: Specifica che sono attive le nuove semantiche, in cui le stringhe con apici inversi vengono eseguite come comandi e le stringhe con virgolette singole sono comandi con stringhe letterali in cui è possibile utilizzare le virgolette doppie per specificare i nomi di file in un gruppo di file.

Delims=: : Specifica un insieme di delimitatori. Tale insieme sostituisce i delimitatori predefiniti (spazi e tabulazioni). 
In pratica, qui stiamo dicendo che le “colonne” del nostro output sono separate dai due punti e che FOR deve incrementare di una lettera dell’alfabeto (partendo da quella specificata poi nella variabile) ogni volta che passa ad analizzare la “colonna successiva”

Tokens=1,2,* : Specifica i token da passare, per ogni riga, al corpo del blocco FOR a ogni iterazione. Determina l'allocazione di nomi di variabile aggiuntivi. L'espressione m-n indica l'intervallo dei token compresi tra la posizione m e la posizione n. Se l'ultimo carattere della stringa specificata dopo tokens= è un asterisco, verrà allocata una variabile aggiuntiva in cui sarà inserito il testo rimanente sulla riga dopo l'ultimo token analizzato.

In sostanza, stiamo dicendo che ci interessano la prima “colonna”, la seconda e poi tutto quello che viene dopo, a prescindere da quanti delimitatori si incontrano da lì in poi.
Ad ogni token viene associata una variabile che parte dalla lettera dell’alfabeto scelta poi (%%f ), quindi le variabili che ci aspettiamo popolate durante il ciclo saranno %%f, %%g, %%h


in (`find /c /v "" %1 ^|FINDSTR /R /C:":[\s]*[0-9]*"`) do ( : utilizziamo l’output del comando tra le back-quotes (a proposito: ALT+96 sul tastierino numerico, per farle) e lo analizziamo riga per riga.

Ora, il comando principale è find /c /v "" %1, ossia, trova il carattere NESSUNO e conta le righe che NON lo contengono (/v) all’interno del file %1, che è il primo parametro che passiamo al nostro batch

Il comando secondario (a cui passiamo l’output del principale mediante una PIPE, qui correttamente preceduta dal carattere di escape), lo uso per filtrare l’output, perché il comando principale ha un output di 3 righe: la prima e l’ultima sono vuote, quindi se non facciamo niente ci troveremo le variabili VUOTE, perché l’ultima esecuzione del ciclo sarebbe su una riga vuota e quindi…


Ma per far capire meglio, eseguiamo in una shell i comandi ad uno ad uno.
Ci alleneremo con il file c:\windows\system32\DISMLog.log che è il log dello strumento di gestione e manutenzione immagini di windows (è un log di sistema, in sostanza, senza che mi dilunghi…).

FIGURA1


Come vedete, il comando conta quante righe NON contengono un carattere NULLO (quindi conta tutte le righe del file), ma vedete che l’output è di 3 righe: la prima e l’ultima sono vuote. A noi interessa solo quella centrale
Ecco quindi che ci viene in aiuto la PIPE ad un altro FIND: FINDSTR, che è in grado di analizzare l’output anche con le regular expressions.

FIGURA2


Come vedete in figura 2 l’output è arrivato pulito… possiamo quindi analizzarlo con il FOR senza temere errori.

Settiamo le variabili

Con le righe

set /A fileLines=%%g set /A Lns=%2 set /A Lns2Skip=!fileLines!-!Lns!

Definiamo le variabili :
fileLines = numero totale di righe
Lns = numero di righe da mostrare dalla fine del file
Lns2Skip = quindi, il numero da saltare (totale – righe da mostrare)

More

A questo punto usiamo il comando more, passando il nome del file da analizzare e il totale delle righe da saltare, preceduto dal + (è un parametro speciale del comando more).

More mostra il file in modalità particolare: ossia mostra una schermata alla volta, lasciando all’utente la possibilità di proseguire (con la barra spaziatrice o con l’invio, sperimentate! – tasto q per “quit”)

FIGURA3


… ed eccoci arrivati alla fine dell’articolo. Per usare il nostro simpatico tail, ci basterà richiamarlo dall’interno dei nostri script o direttamente dal prompt e passare, come primo parametro il nome file e come secondo il numero di righe da mostrare dalla fine.
Tutto qui.
Qui sotto in figura 4 vi mostro le ultime 12 righe del file di log.

FIGURA4



Che dire... spero di aver stuzzicato la vostra fantasia e...

Happy Scripting a tutti!

Nessun commento:

Posta un commento

I commenti sono soggetti a moderazione, prima di essere pubblicati.

Qualsiasi contenuto illecito, immorale o che io ritenga (arbitrariamente) offensivo od inappropriato, verrà cancellato.