Trennen von Variablennamen von Ausgabezeichenfolgen ohne Leerzeichen

Trennen von Variablennamen von Ausgabezeichenfolgen ohne Leerzeichen

Ich habe den folgenden Codeausschnitt, in dem ich Folgendes beabsichtige:

Durchlaufe die Schleife fünfmal;
hole eine Zeile aus einer Datei (bei jeder Iteration muss die nächste Zeile abgerufen werden);
verwende die Zeile als Titel für eine Datei;
setze einen Zeitstempel an den Anfang;
verwende die Zeile als Argument für Ping; drucke einige Sätze, die den Benutzer über den Fortschritt des Codes informieren;

Die Iteration funktioniert bereits.
Wenn ich den sed-Teil überspringe, funktioniert alles, aber ich führe den Ping 5 Mal gegen dasselbe Ziel aus.
Jede Zeile der Datei hosts.txt hat eine einzelne IP-Adresse, die ich anpingen möchte.

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  

Ich glaube, das Problem liegt darin, dass ich etwas bei der Sed-Syntax falsch mache. Wenn ich es direkt bei Bash versuche sed -n 1p hosts, bekomme ich die erste Zeile. Da diese Zahl aber $i sein muss, interpretiert Bash ip als Variable, wenn ich $i direkt vor p setze, anstatt als Variable i plus Argument p dahinter.

Wie kann ich dieses Verhalten korrigieren, ohne die Sache erneut durcheinander zu bringen?

Antwort1

Ich gehe davon aus, dass Sie Bash verwenden, daher sollte das Folgende besser funktionieren:

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 

Ihr Problem ist bash, dass wie bei den meisten externen Shell-Interpretern kshalle Pipeline-Komponenten in einer Subshell abgelegt werden, sodass die outputVariable nach der Festlegung sofort verloren geht.

Beachten Sie auch, dass ich Ihre forSchleife korrigiert habe, die beim Schreiben ein undefiniertes Verhalten aufwies, weil die iVariable nicht initialisiert wurde.

Antwort2

Das Problem ist, wie Sie bemerkt haben, dass sowohl ials auch ipgültige Variablennamen sind. Wenn Sie also den Wert verwenden möchten, $iauf den unmittelbar das Zeichen folgt p, können Sie geschweifte Klammern verwenden, um klar abzugrenzen, wo der Variablenname beginnt und endet:

sed -n "${i}p" hosts.txt | read output

Antwort3

Eine etwas einfachere Lösung ist

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

Beachten Sie das < hosts.txtam Ende der letzten Zeile, nach dem done. Dies wird hosts.txteinmal geöffnet und liest nur die ersten fünf Zeilen daraus. Wie von don_crissti erwähnt, bedeutet die Ausführung in der Schleife, dass Sie die Datei fünfmal sed … hosts.txt | read output lesen . Da dies parallel zum Rest der Schleife (nicht in einer Pipeline) erfolgt, hat der restliche Code in der Schleife Zugriff auf den aus der Datei gelesenen Wert von . Außerdem (wie Don ebenfalls anmerkte) brauchen Sie kein ; erstellthosts.txtread outputoutputtouchcommand>>filefilesofern es nicht bereits existiert.

Beachten Sie, dass dieser Code die neuen Informationen an eine Ihrer hostname.txtDateien anfügt, wenn diese bereits vorhanden ist. Wenn Sie alte Daten verwerfen und von vorne beginnen möchten, tun Sie dies date > "$output.txt"anstelle von date >> "$output.txt".

Seien Sie vorsichtig, wenn Sie unbekannte Daten direkt an übergeben printf. Im (unwahrscheinlichen?) Fall, dass einer Ihrer „Hostnamen“ ein enthält %, wird Ihr Code diesen Namen verstümmeln. Es ist besser, fremde Daten an zu übergeben %s(um eine Zeichenfolge zu drucken).

Sie geben nicht an, ob Sie nur die ersten fünf Zeilen der hosts.txtDatei lesen und dann aufhören möchten oder ob Sie die gesamte Datei lesen möchten und zufällig wissen, dass sie fünf Zeilen lang ist. Wenn Sie die gesamte Datei lesen möchten, tun Sie einfach

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

Wenn Sie das Ende der Datei erreichen, read outputschlägt die Anweisung fehl und die Schleife wird beendet.

verwandte Informationen