2008-10-01 7 views
5

Debido a la forma más tediosa de agregar hosts a ser monitoreados en Nagios (requiere definir un objeto host, a diferencia del programa anterior que solo requería el IP y nombre de host), pensé que sería mejor automatizar esto, y sería un gran momento para aprender Perl, porque todo lo que sé en este momento es C/C++ y Java.Perl: Asir las palabras delimitadas enésima y mestima de cada línea en un archivo

El archivo que he leído desde el siguiente aspecto:

xxx.xxx.xxx.xxx hostname #comments. i.dont. care. about 

Todo lo que quiero son los primeros 2 manojos de caracteres. Obviamente, estos están delimitados por espacios, pero para mayor generalidad, podría ser cualquier cosa. Para hacerlo más general, ¿por qué no el primero y el tercero, o el cuarto y el décimo? Seguramente debe haber alguna acción de expresión regular involucrada, pero dejaré esa etiqueta por el momento, por las dudas.

Respuesta

6

El trazador de líneas único es excelente, si no está escribiendo más Perl para manejar el resultado.

En términos más generales, sin embargo, en el contexto de un programa Perl grande, que sería ya sea escribir una expresión personalizada regular, por ejemplo:

if($line =~ m/(\S+)\s+(\S+)/) { 
    $ip = $1; 
    $hostname = $2; 
} 

... o lo haría con el dividir operador.

my @arr = split(/ /, $line); 
$ip = $arr[0]; 
$hostname = $arr[1]; 

De cualquier manera, agregue la lógica para comprobar la entrada no válida.

+0

Diría que es más idiomático hacer una asignación de lista: por ejemplo, ($ ip, $ hostname) = ($ 1, $ 2) en el primer caso, o ($ ip, $ hostname) = (split '', $ line) [0,1] en el segundo. (El 0,1 es solo en caso de que las personas quieran usar otros números. Si no, ($ ip, $ hostname) = split '', $ line funcionará bien. –

+1

No, más idiomático sería "if (my ($ ip, $ hostname) = $ line = ~/(\ S +) \ s + (\ S +) /) {". – ysth

+1

Ambos tienen razón, pero no soy de la opinión que idiomatic == mejor. – slim

5

Un simple de una sola línea es

perl -nae 'print "$F[0] $F[1]\n";' 

puede cambiar el delimitador con -F

7

Vamos a convertir esto en campo de código! Sobre la base de una excelente respuesta de David, aquí está la mía:

perl -ane 'print "@F[0,1]\n";' 

Editar: Una presentación de golf real, se vería de la misma familia (afeitado de cinco golpes):

perl -ape '$_="@F[0,1] 
"' 

pero eso es menos legible para los propósitos de esta pregunta. :-P

+0

Bien jugado, señor. – Axeman

+0

Gracias! Modifiqué la entrada con algo más golfier, pero probablemente más indescifrable también. :-P –

3

David Nehme dijo:

perl -nae 'print "$F[0] $F[1}\n"; 

que utiliza el interruptor -a. Tuve que buscarlo:

-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. 

aprendes algo todos los días. -n hace que cada línea que se pasa a

LINE: 
    while (<>) { 
     ...    # your program goes here 
    } 

Y finalmente -e es una manera de entrar directamente en una sola línea de un programa. Puede tener más de -e. La mayoría de esto fue una copia de la página del manual perlrun(1).

+0

El modo "autosplit" también se conoce como "modo awk", y el uso de @F como nombre de la matriz se toma de awk. – rjray

6

Aquí hay una solución general (si nos alejamos un poco del código de 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"; 

Normalmente split splits de whitespace. Si eso no es lo que quiere (por ejemplo, el análisis /etc/passwd), se puede pasar un delimitador como una expresión regular:

@fields = (split /:/)[0,2,4..6]; 

Por supuesto, si estás analizar archivos delimitados por dos puntos, lo más probable también es muy posible que este tipo de archivos Don No tienes comentarios y no tienes que despojarlos.

+0

Casi siempre deberías usar chomp en lugar de chop. chop siempre elimina el último carácter de una cadena. chomp elimina el terminador de línea actual (normalmente "\ n") de la cadena, si está presente. Si la línea no termina con el terminador, chomp no hace nada. chop puede eliminar cosas que no esperas. – cjm

+0

La manera Unix es que todos los archivos de texto terminan con una nueva línea. Por lo tanto, nunca leerá una línea sin línea nueva al final, a menos que su archivo esté lleno. Esto se duplica para archivos como los de/etc. :-) –

+0

Simplemente curioso, chop no se refiere a nada en particular. ¿Está conectando el archivo al programa en este caso? – ray

0

Desde que Ray me preguntó, pensé en reescribir todo mi programa sin utilizar la implícita de Perl (excepto el uso de <ARGV>; eso es difícil de escribir a mano). Esto probablemente hará que la gente más feliz del pitón (frenos a pesar :-P):

while (my $line = <ARGV>) { 
    chop $line; 
    $line =~ s/#.*//; 
    next unless $line =~ /\S/; 
    @fields = (split ' ', $line)[0,1]; 
    print join(' ', @fields), "\n"; 
} 

¿Hay algo que perder? Ojalá no. El identificador de archivo ARGV es especial. Hace que se lea cada archivo con nombre en la línea de comando, a menos que no se especifique ninguno, en cuyo caso lee la entrada estándar.

Editar: Oh, lo olvidé. split ' ' es mágico también, a diferencia de split//. Este último solo coincide con un espacio. El primero coincide con cualquier cantidad de espacios en blanco. Este comportamiento mágico se usa por defecto si no se especifica ningún patrón para split. (Algunos dirían, pero ¿qué pasa /\s+/? ' ' y /\s+/ son similares, excepto por cómo se trata espacio en blanco al principio de una línea. Así ' ' realmente es mágico.)

La moraleja de la historia es, Perl es genial si te gusta un montón de comportamiento mágico. Si no tiene una barra, use Python. :-P

+0

chomp en lugar de cortar, solo en caso de que a la última línea del archivo le falte su línea nueva. – ysth

+0

ysth: La pregunta concierne a Unix por lo que puedo decir, y los archivos de texto de Unix siempre deben terminar con una nueva línea. Esto va doble para los archivos. supuestamente en/etc. –

+0

Solía ​​usar religiosamente chomp, durante muchos años, pero he llegado a la conclusión de que es innecesario (para muchos propósitos) y es por eso que chop está allí en primer lugar. –

0

para encontrar a enésima Mes estilo En Línea Nº L --- Ejemplo de etiqueta para encontrar


@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 

Guardar como encontrar label.cmd

el resultado será su Unidad E Etiqueta

Disfrute

Cuestiones relacionadas