janvier
2010
Voici un nouvel exemple d’utilisation de Powershell, histoire de peut-être vous donner envie de pratiquer ce shell bien utile. Dans mes tests, j’ai souvent un processus qui tourne en boucle, d’ailleurs grâce un script posté dans un billet précédent. Ce processus génère un fichier de log à chaque fois, ce qui me fait des dizaines de milliers de fichiers. Pour éviter de remplir le disque dur, je voudrais garder uniquement les fichiers de log qui présentent un intérêt, par exemple ceux qui contiennent le mot ERROR. C’est facile en PowerShell, avec un peu de pratique on peut le faire directement sur la ligne de commande :
(le message d’erreur vient d’un fichier en cours d’écriture)
Après avoir mis cela au point sur la ligne de commande comme ci-dessus, je met cette commande dans un fichier de script pour la réutiliser plus tard :
On peut noter dans le script la barre verticale, indiquant un pipeline. Le pipeline passe la sortie de la première commande (la liste de fichier résultant de dir) à la deuxième commande qui consiste en un foreach. Dans le bloc du foreach on référence l’objet courant (le fichier) avec la variable spéciale $_. foreach est un alias pour ForEach-Object (et peut encore se raccourcir en « % », comme dans l’exemple ci-dessous).
Simple, non ?
Un autre exemple dans la même veine consiste à supprimer les fichiers .DATA générés par mes expériences, mais pas trop tôt afin de ne pas interférer avec les analyses en cours – j’attends donc 30 minutes par exemple. Voici un script pour faire cela (j’ai encadré en rouge le calcul sur les dates) :
Voilà le résultat sur la console :
Il restera à mieux formater le taux de génération !
Le même script sous forme de code copiable, au cas où ca vous intéresse de le récupérer :
$DELAY=60*15
$total_deleted = 0
while ($True) {
$deleted = 0
dir c:\data -recurse -include *.data | % {
if ( ((get-date)-$_.LastWriteTime).TotalMinutes -gt 30) {
del $_ ; $deleted += 1
}
}
$total_deleted += $deleted
$generation_rate = ($deleted / $DELAY) * 60
write-host (get-date), `
"total already deleted ", $total_deleted, `
" generation rate ", $generation_rate, " / minute"
Sleep -Seconds $DELAY
}
Voilà des exemples que j’aurais été bien incapable de réaliser en DOS, et qui sont très faciles à faire en PowerShell.
Et vous, quels sont les scripts qui vous simplifient la vie ?
6 Commentaires + Ajouter un commentaire
Commentaires récents
- Des tableaux pour l’intégration d’un équipier dans une équipe Scrum dans
- Rétrospectives, la directive première dans
- Des tableaux pour l’intégration d’un équipier dans une équipe Scrum dans
- Des tableaux pour l’intégration d’un équipier dans une équipe Scrum dans
- Des tableaux pour l’intégration d’un équipier dans une équipe Scrum dans
OK, je commence à y voir légèrement plus clair dans ces deux types de liaisons !
Bruno
« par contre ce n’est pas trivial de savoir si tel ou tel type d’objet est accepté «
Si j’ai bien compris, tu peux faire ceci pour le savoir :
(get-help select-string -full).returnValues
(get-help Del -full).inputtypes
Ensuite le cmdlet Get-Member prend tout son sens, mais il faut tout de même connaitre les classes que l’on manipule, on aborde donc le niveau avancé du scripting sous PowerShell.
Si par exemple un des objets ou une classe contient une information utile, mais ne propose pas de nom de propriété attendu par un cmdlet, on peut utiliser Add-Member pour adapter l’objet au besoin.
C’est une conception remarquable.
Pour la liaison byValue on récupère l’objet dans son intégralité et pas une simple information telle qu’un nom du fichier par exemple.
Ce qui permet en interne d’appeler des méthodes sur l’objet récupéré, on évite ainsi de déclarer autant de paramètres qu’il y a de membres qui nous intéressent.
Enfin, on peut combiner les 2 types, byValue et byPropertyName, afin d’augmenter les possibilités de réussite lors de la liaison, sous réserve que cela ait un sens.
On peut utiliser PowerShell sans connaitre cette mécanique, mais une fois connue, on l’appréhende différemment.
Merci Laurent pour les références, si j’ai bien compris http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry, on peut assez facilement déterminer si un cmdlet accepte le pipeline en input grace à l’aide, par contre ce n’est pas trivial de savoir si tel ou tel type d’objet est accepté (il faut passer par du TraceCommand etc.). Ca correspond à mon exemple où cela ne me sautait pas aux yeux que le type AliasInfo sortant de Select-String pouvait passer directement en entrée de DEL…
Pour l’autre article, j’ai plus de mal, j’y reviendrai + tard !
>>je n’aurais pas eu l’idée de faire aussi simple
Le « truc » est qu’on pense souvent en procédural, et PowerShell c’est un peu comme Linq sous Dotnet, ça marche pas comme ça.
Sur le principe il n’y a pas de branchement mais plutôt des filtres.
Mais je reconnais que je prend souvent dans un premier temps cette approche autour de Foreach qui facilite l’écriture du « premier jet » d’un traitement.
Ensuite j’optimise en lisant la documentation, car on ne pas tout connaître par coeur sur un tel produit.
Je me permets de citer ces deux de posts du blog de Keith Hill, le chef projet de PSCX (open source):
Understanding ByValue Pipeline Bound Parameters
http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry
Understanding ByPropertyName Pipeline Bound Parameters
http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry
A leur lecture on comprend mieux la mécanique de liaison des paramètres dans le pipeline sous PowerShell.
Merci Laurent pour l’exemple et la remarque sur l’utilisation directe de DEL : je n’aurais pas eu l’idée de faire aussi simple !
Salut,
>>Et vous, quels sont les scripts qui vous simplifient la vie ?
J’en utilise de nombreux, par exemple celui-ci pour construire, à partir d’un référentiel svn, un fichier des révisions :
#repository local <br />
#La config de svn pointe par défaut sur l'URL adéquate <br />
cd g:psadd-lib <br />
#Récupère une partie des logs au format XML <br />
svn log -r 76:111 --xml|Out-File -Encoding OEM g:pstemplog.xml <br />
<br />
$res=[xml](gc g:pstemplog.xml) <br />
#Extrait du document XML, les informations souhaités <br />
$Res|foreach { $_.log.logentry }|% {$_.msg}| Out-File -Encoding default g:pstemplog.txt <br />
Sinon pour ton premier exemple, on peut aussi éviter l’usage du Foreach, si l’affichage des noms de fichiers restant n’est pas nécessaire:
#Whatif n'effectue pas le traitement, mais le simule. <br />
Dir *.bak|Select-String -Pattern ERROR -List -NotMatch|Del -whatif <br />