Ich habe ein Skript, das einen Befehl auf einem Remote-Server über SSH ausführt. Ich möchte die Zeichenfolge jeder Zeile der Ausgabe voranstellen Remote:
, aber ich möchte nicht, dass jede Zeile verzögert wird, bis die gesamte Zeile verfügbar ist. Hier ist die Ausgabe meines Befehls:
$ myproject-db-push mein_Datenbankname Exportieren aus der Datenbank... Fertig Daten archivieren... Fertig Archiv wird auf Remote-Speicher hochgeladen... Fertig Ausführen des Installationsskripts auf der Remote- Remote: Archiv in temporäres Verzeichnis dekomprimieren... Fertig Remote: Verwendete Datenbank: my_database_name Remote: Sammlungen löschen: Fernbedienung: - my_collection_foo Fernbedienung: - my_collection_bar Remote: Neue Daten importieren... Fertig
In diesem Fall verwende ich sed
Folgendes:
echo "$INSTALLCMD" | ssh -T "deploy@$SERVER" | sed -u "s/^/Remote: /"
Das Problem ist, wie ich bereits erklärte, dass keineteilweiseZeilen werden auf dem Bildschirm ausgegeben. Wenn ich das | sed
Teil entferne, funktioniert es wie erwartet. Zunächst wird Folgendes geschrieben:
Neue Daten importieren...
Und wenige Sekunden später ist die Zeile vervollständigt:
Neue Daten importieren... Fertig
Ich gehe davon aus, sed
dass es nur zeilenweise arbeiten kann. Ich habe versucht, es auf ungepuffert einzustellen, aber es wartet immer noch auf ganze Zeilen. Gibt es eine andere Möglichkeit, dies zu erreichen?
Antwort1
Das ist etwas knifflig, weil all diese Dienstprogramme ( sed
,,, ) zeilengepuffert sind. Das heißt, sie drucken die Ausgabe erst, wenn die Zeile beendet ist (ein Zeilenumbruch aufgetreten ist). Sie können die Eingabe nicht Zeichen für Zeichen lesen awk
.grep
Deshalb habe ich zum Testen eine kleine Sequenz erstellt, die Ihr Verhalten simuliert:
{
echo -n "first task: "
sleep 2
echo "done"
echo -n "second task: "
sleep 2
echo "done"
}
Wie in Ihrer Frage wird first task:
nach 2 Sekunden Folgendes gedruckt done
. Probieren Sie es selbst aus, indem Sie es in Ihr Terminal kopieren.
Lösung:
Fügen Sie hinter Ihrem Befehl Folgendes hinzu:
IFS=
command | { x=1; while IFS= read -d'' -s -N 1 char; do
[ $x ] && printf "Remote: "
printf "$char"
unset x
[ "$char" == "
" ] && x=1
done; }
Erläuterung:
Das read
eingebaute von bash
kann Eingaben zeichenweise lesen. Der Teil read -d'' -s -N 1 char
deaktiviert das Trennzeichen -d''
, aktiviert den stillen Modus -s
und liest immer nur 1 Zeichen -N 1
in die Variable ein $char
. Dann prüft der Befehl, ob die Variable $x
existiert. Wenn ja, sind wir in einer neuen Zeile und drucken das „Präfix“. Dann drucken wir das Zeichen. Aufheben $x
. Dann prüft die letzte Anweisung, ob das Zeichen ein Zeilenumbruch ist. Wenn es ein Zeilenumbruch ist, wird $x
auf gesetzt 1
und in der nächsten Schleife wird das „Präfix“ gedruckt.
Das Ganze kann getestet werden, indem man die beiden Sequenzen aneinanderreiht:
{
echo -n "first task: "
sleep 2
echo "done"
echo -n "second task: "
sleep 2
echo "done"
} | { x=1; while IFS= read -d'' -s -N 1 char; do
[ $x ] && printf "Remote: "
printf "$char"
unset x
[ "$char" == "
" ] && x=1
done; }