Ich habe das folgende Muster verwendet, um mehrzeilige Nachrichten in einem Bash-Skript an das Terminal zu drucken.
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
Das hat funktioniert - bis vor ein paar Tagen hat das Muster einfach aufgehört zu funktionieren. Mit aufgehört zu arbeiten meine ich, als bash auf diese Heredoc-Ausdrücke im Skript stieß - es scheint einfach nichts zu tun - keine Ausgabe.
Das einzige, was ich mir vorstellen kann, was sich in den letzten Tagen geändert hat, ist, dass die Umgebung, in der die Skripte ausgeführt werden, ein Ubuntu 14.04 Live-USB ist, im Gegensatz zu "vollständigen" Installationen.
Dann stellte ich fest, dass der Heredoc beim Verschieben vor der Skriptanweisung set -o errexit
wieder funktioniert. dh das funktioniert nicht
#!/bin/bash
set -o errexit
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
Ergebnis: (nichts)
Aber das funktioniert
#!/bin/bash
read -d '' message <<- EOF
this is a
mulitline
message
EOF
echo "$message"
Ergebnis
$ sudo ./script.sh
this is a
mulitline
message
- bash --version -
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)
\0
keine leere Zeichenfolge.-d
, ist das Trennzeichen\0
(ein NUL-Byte). Ein Sonderfall ist meistens das Ergebnis eines Codierungsunfalls (obwohl derbash
Betreuer dies nicht zugibt und erklärt, warum es nicht dokumentiert ist ).\0
der Fall - und das schlägt nicht immer fehl. Sie können beispielsweiseread -d ''
die Ausgabe von verarbeitenfind ... -print0
.Der Exit-Code des Lesebefehls ist 1, wenn die Markierung für das Dateiende (EOF) erreicht ist. Dies ist immer dann der Fall , wenn das Trennzeichen in diesem speziellen Fall, in dem der Quelldatenstrom ein Heredoc ist, der kein \ 0 enthalten kann,
-d
null''
ist.Dass der Exit-Wert ein Fehler ist (nicht 0), lässt den Skript-Exit mit einem AND / OR-Konstrukt vermieden werden:
Dadurch wird die Nachricht an die Konsole gesendet, und es wird dennoch vermieden, sie mit zu beenden
errexit
.Aber da wir auf diesem Weg sind, um zu reduzieren, warum nicht direkt nutzen:
Kein Lesebefehl ausgeführt (mehr Geschwindigkeit), keine Variable erforderlich, kein Fehler im Exit-Code, weniger zu wartender Code.
quelle
||
wie man das Beenden des Skripts verhindert. Am Ende habe icherrexit
das Skript komplett entfernt. Ich hatte Probleme damit, nicht das Beenden auszulösen, wenn es sollte - es scheint also zu schwierig, um nützlich zu sein. Ich habe auch das einfachere Muster mit berücksichtigtcat <<- EOF message EOF
. Es war einfach schön, die Nachricht in einer Variablen zu haben, die bei Bedarf an eine Funktion übergeben werden konnteLiest stdin bis zum ersten nicht entkoppelten (wie Sie nicht hinzugefügt haben
-r
) NUL-Zeichen oder dem Ende der Eingabe und speichert die Daten nach$IFS
und Backslash-Zeichenverarbeitung in$message
(ohne das Trennzeichen).Wenn in der Eingabe kein nicht entkoppeltes Trennzeichen gefunden wird, ist der Beendigungsstatus
read
ungleich Null. Es wird nur 0 (Erfolg) zurückgegeben, wenn ein vollständiger, abgeschlossener Datensatz gelesen wird.Dies ist am nützlichsten für den Umgang mit NUL-getrennten Datensätzen wie der Ausgabe von
find -print0
(obwohl Sie dann eineIFS= read -rd '' record
Syntax benötigen ).Hier müssen Sie ein NUL-Trennzeichen in Ihr Here-Dokument aufnehmen
read
, damit Sie erfolgreich zurückkehren können. Dies ist jedoch nicht möglich, mitbash
dem NUL-Zeichen aus Here-Dokumenten entfernt werden (das ist zumindest besser als dasyash
, was alles nach dem ersten NUL entfernt, oder ksh93, das in eine Endlosschleife einzutreten scheint, wenn ein Here-Dokument ein NUL enthält).zsh
ist die einzige Shell, die eine NUL in ihren hier enthaltenen Dokumenten haben oder in ihren Variablen speichern oder NUL-Zeichen in Argumenten an ihre eingebauten / Funktionen übergeben kann. Inzsh
können Sie tun:(
zsh
Verstehe auchread -d ''
als NUL-Trennzeichen wiebash
. Funktioniertread -d $'\0'
auch in,bash
aber das übergibt ein leeres Argument, um zuread
mögen,read -d ''
dabash
NUL-Bytes in seiner Befehlszeile nicht unterstützt werden).(Beachten Sie, dass es danach ein zusätzliches Zeilenumbruchzeichen gibt.
$NUL
)In
bash
können Sie ein anderes Zeichen verwenden:Sie können aber auch Folgendes tun:
Das erlaubt immer noch keine NUL-Zeichen. Dies ist jedoch Standardcode, sodass Sie sich nicht auf den zsh / bash-spezifischen Code verlassen müssen
read -d
. Beachten Sie auch, dass alle nachgestellten Zeilenumbrüche entfernt werden.ksh93
Wenn dies nicht dercat
Fall ist, bedeutet dies, dass ein zusätzlicher Prozess und Befehl erzeugt wird.quelle
read
In diesem Fall bedeutet dies, dass ein Wert ungleich Null zurückgegeben wird, da kein Trennzeichen gefunden wurde, nicht wahr?Wenn Sie verwenden
set -o errexit
und Ihr Skript kaputt geht, bedeutet dies, dass etwas nicht stimmt.Hier ist es
read
, was Ihre Eingabe nicht richtig lesen kann.In
bash
, wenn Sieread -d ''
dieread
builtin die Null - Zeichen verwendet\0
als Leitungsabschluss. Wenn\0
Ihre Eingabe keine enthält ,read
werden daher alle Eingaben in diemessage
Variable eingelesen und ein Exit-Status ungleich Null zurückgegeben, um anzuzeigen, dass ein Fehler aufgetreten ist:druckt nichts während:
gibt dir
1
.read
gibt auch den Status ungleich Null zurück, wenn EOF erreicht wird. Dies wird jedoch verwendet, um anzuzeigen, dass bei Verwendungread
mit einerwhile
Schleife keine Eingabe mehr zu lesen ist , sodass diewhile
Schleife beendet werden kann. Es ist nicht relevant für Ihr Problem.quelle
read
Gesichtsausdruck das Drehbuch brach. Aber das ist ein guter Punkt, der auch Nicht-Null gelesen verlässt , wenn sie mit einem gebrauchtenread
,while
Schleife. Aus diesem Grund halte ich es nicht fürset -o errexit
zuverlässig, da Befehle manchmal als Teil des normalen Programmflusses ungleich Null zurückgeben müssenif read ...
read
die bei einem nicht gefundenen Trennzeichen mit einem Fehler zurückkehrt (und die Schleife verlässt) (obwohl ich zustimmen würde, dass dies wahrscheinlich nur mehr Verwirrung stiftet).