giovedì 10 febbraio 2011

Come prendere l'output di un comando e impostarlo come variabile. - Lo Scriptomane - livello MEDIO

Buongiorno, ecco il secondo articolo di questo mio piccolo spazio dedicato allo scripting che promette di essere una guida per chi vuole dedicarsi ad un approccio innovativo per la gestione delle operazioni di amministrazione di computer, reti e quant'altro.

Al contrario del mio "cugino" americano: "the Scripting Guy", che ammiro molto e che è stato per me molte volte una guida, io cerco di non scomodare il signor VBScript quando non è proprio necessario.

Windows ha un cuore di scripting dalle potenzialità spesso inespresse / non documentate: il batch.

Oggi vedremo un argomento controverso a cui viene spesso data la risposta "non si può":
Come prendere l'output di un comando e impostarlo come variabile.

in batch si usa SET per impostare variabili ambiente (usate il comando SET senza parametri per visualizzare una lista completa di variabili ambiente presenti nel vostro PC, oppure "SET a" per vedere solo quelle che iniziano con a e via dicendo...).

il comando SET, come tutti gli altri comandi, può essere messo in un ciclo del comando FOR e il comando FOR è un tipo in gamba ad analizzare l’output dei comandi. Basta lanciare il comando che vogliamo analizzare dalle sue “parentesi”. Oggi vedremo anche un altro aspetto che di solito spinge gli scripters a redirigere l’output di comandi prima verso file di testo: il PIPING* all’interno del FOR mediante l’uso dei caratteri di ESCAPE*

Ma vediamo subito nella pratica.
Una delle operazioni più comuni che vorrebbero ottenere i sistemisti da un linguaggio di scripting è ottenere l’indirizzo IP del computer in uso, la sua netmask e il gateway predefinito. OK, mettete quanto segue in un file di batch:

@echo off
setlocal EnableDelayedExpansion
SET i=0
FOR /F "usebackq delims=: tokens=1,2,*" %%a IN (`IPCONFIG ^| FINDSTR /I "Indirizzo Subnet Gateway"`) DO (
set var!i!=%%b
SET /A i=!i!+1
)
echo var0: !var0!
echo var1: !var1!
echo var2: !var2!
pause
in var0 c'è l'IP, in var1 c'è la MASK, in var2 il gateway.

A questo punto urge una spiegazione, line by line, command by command:

@echo OFF -> evita che nell'output VISIVO, si vedano i comandi lanciati.

setlocal EnableDelayedExpansion -> Abilita l'espansione delle variabili all'interno del ciclo FOR (altrimenti sarebbero tutte VAR0 o VAR2 che si sovrascrivono, perchè le operazioni sulle variabili vengono eseguite tutte prima del ciclo FOR effettivo... un guazzabuglio: fidatevi di me). Quando si abilita questa caratteristica, le variabili vanno richiamate con !nomeVar! e non più con %nomeVar%. IMPORTANTE!

SET i=0 -> imposta la variabile %i% uguale a 0, ci servirà come "pezzo" del nome variabile.

... qui procedo più con calma
FOR /F "usebackq delims=: tokens=1,2,*" %%a ... -> qui diciamo al FOR di usare le estensioni dei comandi "usebackq", di analizzare l'input trovando i separatori ":" e di usare il primo valore prima di ":" come prima variabile, il secondo valore dopo i ":" come seconda (%%b, perchè va in ordine alfabetico) e, se anche trovasse un terzo ":" e un quarto ":", tutto ciò che viene dopo il terzo ":" come terza variabile.





... IN (`IPCONFIG ^| FINDSTR /I "Indirizzo Subnet Gateway"`) DO ( -> qui dico al comando FOR di analizzare riga per riga dell'output del comando incluso in apici inversi " ` " (si ottengono con il codice ASCII 96, quindi: tengo premuto ALT e scrivendo 96, poi rilascio ALT e "appare magicamente").
Il comando che inserisco dovrebbe essere IPCONFIG | FINDSTR /I "Indirizzo Subnet Gateway" OVVERO: passo l'output del comando ipconfig al comando FINDSTR, dicendo che mi estragga SOLO le righe che contengono "Indirizzo", "Subnet" oppure "Gateway". Però il PIPING mi manderebbe in errore il comando FOR, se non fosse ESCAPED dal carattere ^. Infatti l'interprete BATCH analizzerebbe la richiesta come "tutto quello che si trova prima del PIPE è il primo comando sulla riga, tutto ciò che si trova dopo il secondo. Il comando terminerebbe con un erroraccio ininterpretabile: " %%a non atteso. ". :-)

Tutte le righe che seguono la parentesi aperta e che precedono la parentesi chiusa sono eseguite ciclicamente dal FOR, quindi per ogni riga dell'output del comando sopra descritto.

SET var!i!=%%b -> qui dico di impostare la variabile varX (dove X è il valore attuale della variabile !i! che abbiamo inizializzato prima del FOR e che al primo ciclo è 0) con la SECONDA variabile nell'analisi di FOR della riga, ovvero tutto ciò che è successivo al primo ":" della riga analizzata.

SET /A i=!i!+1 ->incremento la variabile !i! algebricamente (/A) di uno rispetto al suo valore attuale.

ed ecco spiegato il "trucco". Spero che vi sia utile in futuro! :-)


P.S.: problemi con gli spazi? non li volete? usate le sostituzioni. Es. !var0: =! ritornerà la variabile var0 senza spazi (spazio uguale niente).

--
Diego Castelli
Verona - Italy
-------------------------
MCSA 2003, MCTS Forefront, MCP
HP AIS, HP APS

Windows come Linux - Lo Scriptomane - livello MEDIO

Buongiorno a tutti, scrivo questo post per mostrare a tutti alcune funzionalità della shell dei comandi windows, che la rendono (combinata con gli altri linguaggi di script supportati, come vbscript e jscript) potente come la tanto chiacchierata shell di linux.
Tanto per cominciare voglio dire che io sono un bilingue dei sistemi operativi. Mi piacciono molti sistemi e uso volentieri le più disparate versioni di OS (non solo *NIX!) in base all'obiettivo che cerco di raggiungere.
Le mie competenze che voglio qui condividere mi hanno valso il soprannome di scriptomane, tra i miei colleghi, ed alcuni sistemisti linux con cui ho collaborato hanno osservato: ma tu usi windows come linux!
Oggi voglio parlare delle alternative windows batch al potentissimo comando unix GREP. Lo sapevate che anche in windows é possibile analizzare l'output di un comando, ad esempio, con le regular expressions? I comandi batch FIND e FINDSTR permettono l'uno uno startup semplice per chi non ha bisogno di regular expressions o ricerche multiple, l'altro lo stadio più avanzato della ricerca nei files, nelle directory e nell'output dalla pipe.
Per chi non lo sapesse, la pipe é un modo di redirezione dell'output che proviene dai sistemi *nix e che era già implementato in DOS da una certa versione.
Un semplice modo per passare l'output di un comando ad un secondo comando é
Comando1 | Comando2, ad esempio:
Netstat -n | FIND ":25 "
Mostrerà tutte le connessioni di rete attive sulla porta 25, sia che esse siano in ingresso, sia che siano in uscita.
Dir /A-D /B | Findstr /I /R "[sa].*[bg]\..* [a-fzx]*\..*"
Cerca tutti i files nella directory corrente che non sono directory (/A-D), con qualsiasi estensione e il cui nome
  1. cominci per s oppure per a e finisca per b oppure per g, con qualsiasi estensione.
  2. oppure contenga solo a, b, c, d, e, f, z oppure x, con qualsiasi estensione.
Notate lo spazio che separa le due regular expressions usate per analizzare l'output del comando DIR.


Ed ecco che abbiamo descritto una funzione evolutissima della shell command-line di Windows.
A mio avviso è il metodo perfetto per ottenere output filtrati ulteriormente analizzabili/utilizzabili da altri script.

Si può anche iserire i risultati in un ciclo for per operare azioni sulla base di ogni riga outputtata... ma questo ve lo dico in un altro post....


Ciao!