Separar nombres de variables de cadenas de salida sin espacios en blanco

Separar nombres de variables de cadenas de salida sin espacios en blanco

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, kshcolocan todos los componentes de la canalización en un subshell, por lo que la outputvariable se pierde inmediatamente después de configurarse.

Tenga en cuenta también que corregí su forbucle que, tal como está escrito, tenía un comportamiento indefinido porque la ivariable no estaba inicializada.

Respuesta2

El problema es que, como habrá observado, ambos iy ipson nombres de variables válidos. Entonces, si desea usar el valor $iinmediatamente 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.txtal final de la última línea, después de done. Esto se abre hosts.txtuna 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.txtarchivo cinco veces. Dado que read outputes paralelo al resto del bucle (no en una canalización), el resto del código del bucle tendrá acceso al valor de outputlectura del archivo. Además (como también señaló don), no es necesario touch; crearácommand>>filefilesi no existe ya.

Tenga en cuenta que si uno de sus hostname.txtarchivos 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.txtarchivo 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 outputdeclaración fallará y el ciclo finalizará.

información relacionada