Tengo el siguiente fragmento de código donde pretendo:
Iterar 5 veces el ciclo;
obtener una línea de un archivo (en cada iteración necesito obtener la siguiente línea);
utilizar la línea como título de un archivo;
ponga una marca de tiempo al principio;
use la línea como argumento para ping; imprimir algunas frases informando al usuario sobre el progreso del código;
La iteración ya funciona.
Si me salto la parte sed, todo funciona, pero ejecuto el ping 5 veces contra el mismo objetivo.
Cada línea del archivo hosts.txt tiene una única dirección IP a la que pretendo hacer ping.
for ((i>=1;i<=5;i++))
do
sed -n "$i p" hosts.txt | read output
touch "$output.txt"
date >> "$output.txt"
printf "\nComeçando o teste de $output."
printf "\nTeste em andamento."
ping -c 10 -i 1 "$output" >> "$output.txt"
done
Creo que el problema es que estoy haciendo algo mal con la sintaxis sed. Si pruebo bash directamente sed -n 1p hosts
, obtengo la primera línea. Pero como necesito que ese número sea $i, si pongo $i justo antes de p, bash interpreta ip como una variable en lugar de la variable i más el argumento p después.
¿Cómo puedo corregir este comportamiento y no volver a estropearlo?
Respuesta1
Supongo que estás usando bash, por lo que esto debería funcionar mejor:
for ((i=1;i<=5;i++))
do
sed -n "$i p" hosts.txt | (
read output
touch "$output.txt"
date >> "$output.txt"
printf "\nComeçando o teste de $output."
printf "\nTeste em andamento."
ping -c 10 -i 1 "$output" >> "$output.txt"
)
done
El problema que estaba sufriendo es que bash
, como la mayoría de los intérpretes de shell externos, ksh
colocan todos los componentes de la canalización en un subshell, por lo que la output
variable se pierde inmediatamente después de configurarse.
Tenga en cuenta también que corregí su for
bucle que, tal como está escrito, tenía un comportamiento indefinido porque la i
variable no estaba inicializada.
Respuesta2
El problema es que, como habrá observado, ambos i
y ip
son nombres de variables válidos. Entonces, si desea usar el valor $i
inmediatamente seguido del carácter p
, puede usar llaves flexibles para delimitar claramente dónde comienza y termina el nombre de la variable:
sed -n "${i}p" hosts.txt | read output
Respuesta3
Una solución un poco más sencilla es
for ((i=1; i<=5; i++))
do
read output
date >> "$output.txt"
printf "\nComeçando o teste de %s." "$output"
printf "\nTeste em andamento."
ping -c 10 -i 1 "$output" >> "$output.txt"
done < hosts.txt
Tenga en cuenta que < hosts.txt
al final de la última línea, después de done
. Esto se abre hosts.txt
una vez y solo lee las primeras cinco líneas. Como lo mencionó don_crissti, hacerlo sed … hosts.txt | read output
en bucle significa que estás leyendo el hosts.txt
archivo cinco veces. Dado que read output
es paralelo al resto del bucle (no en una canalización), el resto del código del bucle tendrá acceso al valor de output
lectura del archivo. Además (como también señaló don), no es necesario touch
; crearácommand >> file
file
si no existe ya.
Tenga en cuenta que si uno de sus hostname.txt
archivos ya existe, este código le agregará la nueva información. Si desea descartar datos antiguos y comenzar desde cero, hágalo date > "$output.txt"
en lugar de date >> "$output.txt"
.
Tenga cuidado al pasar datos desconocidos directamente a printf
. En el (¿improbable?) caso de que uno de sus “nombres de host” tenga un %
nombre, su código confundirá ese nombre. Es mejor pasar datos externos %s
(para imprimir una cadena).
No dice si desea leer solo las primeras cinco líneas del hosts.txt
archivo y luego detenerse, o si desea leer el archivo completo, y resulta que sabe que tiene cinco líneas. Si desea leer el archivo completo, simplemente haga
while read output
do
date >> "$output.txt"
printf "\nComeçando o teste de %s." "$output"
printf "\nTeste em andamento."
ping -c 10 -i 1 "$output" >> "$output.txt"
done < hosts.txt
Cuando llegue al final del archivo, la read output
declaración fallará y el ciclo finalizará.