Perl: Saisir les mots délimités nième et mois de chaque ligne d'un fichier
Question
En raison de la manière plus fastidieuse d'ajouter des hôtes à surveiller dans Nagios (il est nécessaire de définir un objet hôte, par opposition au programme précédent qui ne nécessitait que l'adresse IP et le nom d'hôte), j'ai donc pensé qu'il serait préférable d'automatiser cette opération. Ce serait un bon moment pour apprendre Perl, car tout ce que je sais pour le moment, c'est C / C ++ et Java.
Le fichier que j'ai lu ressemble à ceci:
xxx.xxx.xxx.xxx hostname #comments. i.dont. care. about
Tout ce que je veux, ce sont les 2 premiers groupes de caractères. Celles-ci sont évidemment délimitées par un espace, mais par souci de généralité, cela pourrait aussi bien être n'importe quoi. Pour le rendre plus général, pourquoi pas les premier et troisième, ou quatrième et dixième? Il doit sûrement y avoir une action regex impliquée, mais je laisserai cette balise éteinte pour le moment, juste au cas où.
La solution
Le one-liner est génial, si vous n’écrivez pas plus de Perl pour gérer le résultat.
Plus généralement, dans le contexte d'un programme Perl plus important, vous pouvez écrire une expression régulière personnalisée, par exemple:
if($line =~ m/(\S+)\s+(\S+)/) {
$ip = $1;
$hostname = $2;
}
... ou vous utiliseriez l'opérateur fractionné .
my @arr = split(/ /, $line);
$ip = $arr[0];
$hostname = $arr[1];
Quoi qu'il en soit, ajoutez une logique pour vérifier si une entrée est invalide.
Autres conseils
Transformons cela en code golf! D'après l'excellente réponse de David, voici la mienne:
perl -ane 'print "@F[0,1]\n";'
Modifier: une vraie soumission de golf ressemblerait davantage à ceci (effacer cinq coups):
perl -ape '$_="@F[0,1]
"'
mais c'est moins lisible aux fins de cette question. :-P
Voici une solution générale (si nous nous éloignons un peu du code-golf).
#!/usr/bin/perl -n
chop; # strip newline (in case next line doesn't strip it)
s/#.*//; # strip comments
next unless /\S/; # don't process line if it has nothing (left)
@fields = (split)[0,1]; # split line, and get wanted fields
print join(' ', @fields), "\n";
Normalement split
se divise en espaces. Si ce n'est pas ce que vous voulez (par exemple, analyser /etc/passwd
), vous pouvez passer un délimiteur sous forme de regex:
@fields = (split /:/)[0,2,4..6];
Bien sûr, si vous analysez des fichiers délimités par des deux-points, il est également probable que ces fichiers ne contiennent pas de commentaires et que vous ne devez pas les supprimer.
Un one-liner est simple
perl -nae 'print "$F[0] $F[1]\n";'
vous pouvez changer le délimiteur avec -F
David Nehme a déclaré:
perl -nae 'print "$F[0] $F[1}\n";
qui utilise le commutateur -a
. Je devais regarder celui-là:
-a turns on autosplit mode when used with a -n or -p. An implicit split
command to the @F array is done as the first thing inside the implicit
while loop produced by the -n or -p.
vous apprenez quelque chose tous les jours. -n provoque le passage de chaque ligne à
LINE:
while (<>) {
... # your program goes here
}
Et finalement -e
est un moyen d'entrer directement une seule ligne d'un programme. Vous pouvez avoir plus que perlrun(1)
. Il s’agissait pour l’essentiel d’une copie de la <=> page de manuel.
Depuis que Ray m'a demandé, je pensais réécrire tout mon programme sans utiliser l'implicite de Perl (à l'exception de l'utilisation de <ARGV>
; difficile à écrire à la main). Cela rendra probablement les gens de Python plus heureux (malgré les accolades :-P):
while (my $line = <ARGV>) {
chop $line;
$line =~ s/#.*//;
next unless $line =~ /\S/;
@fields = (split ' ', $line)[0,1];
print join(' ', @fields), "\n";
}
Y at-il quelque chose que j'ai raté? Heureusement non. Le ARGV
filehandle est spécial. Chaque fichier nommé sur la ligne de commande est lu, sauf si aucun fichier n'est spécifié, auquel cas il lit les entrées standard.
Edit: Oh, j'ai oublié. split ' '
est magique aussi, contrairement à split / /
. Ce dernier correspond juste à un espace. Le premier correspond à n’importe quelle quantité d’espace. Ce comportement magique est utilisé par défaut si aucun motif n'est spécifié pour split
. (Certains diraient, mais qu'en est-il de /\s+/
? ' '
et <=> sont similaires, sauf en ce qui concerne le traitement des espaces au début d'une ligne. Donc, <=> est vraiment magique. )
La morale de l'histoire est que Perl est excellent si vous aimez les comportements magiques. Si vous n'en avez pas, utilisez Python. :-P
Pour rechercher le nième au mois dans la ligne n ° L - Exemple de recherche d'étiquette
@echo off
REM Next line = Set command value to a file OR Just Choose Your File By Skipping The Line
vol E: > %temp%\justtmp.txt
REM Vol E: = Find Volume Lable Of Drive E
REM Next Line to choose line line no. +0 = line no. 1
for /f "usebackq delims=" %%a in (`more +0 %temp%\justtmp.txt`) DO (set findstringline=%%a& goto :nextstep)
:nextstep
REM Next line to read nth to mth Character here 22th Character to 40th Character
set result=%findstringline:~22,40%
echo %result%
pause
exit /b
Enregistrer sous find label.cmd
Le résultat sera votre étiquette de lecteur E
Profitez