In einem Shell-Skript ...
Wie erfasse ich stdin in einer Variablen, ohne nachfolgende Zeilenumbrüche zu entfernen?
Im Moment habe ich versucht:
var=`cat`
var=`tee`
var=$(tee)
In allen Fällen $var
wird nicht die nachfolgende Newline des Eingabestreams angezeigt. Vielen Dank.
AUCH: Wenn die Eingabe keinen nachgestellten Zeilenumbruch enthält, darf die Lösung keinen hinzufügen .
UPDATE IM LICHT DER AKZEPTIERTEN ANTWORT:
Die endgültige Lösung, die ich in meinem Code verwendet habe, lautet wie folgt:
function filter() {
#do lots of sed operations
#see https://github.com/gistya/expandr for full code
}
GIT_INPUT=`cat; echo x`
FILTERED_OUTPUT=$(printf '%s' "$GIT_INPUT" | filter)
FILTERED_OUTPUT=${FILTERED_OUTPUT%x}
printf '%s' "$FILTERED_OUTPUT"
Wenn Sie den vollständigen Code sehen möchten, besuchen Sie bitte die Github-Seite für expandr , ein kleines Open-Source -Filter- Shell-Skript zur Erweiterung von Git-Schlüsselwörtern , das ich aus Gründen der Informationssicherheit entwickelt habe. Gemäß den Regeln, die in .gitattributes- Dateien (die branchenspezifisch sein können) und in git config festgelegt sind , leitet git jede Datei beim Ein- und Auschecken aus dem Repository durch das Shell-Skript expandr.sh . (Aus diesem Grund war es wichtig, nachfolgende oder fehlende Zeilenumbrüche beizubehalten.) Auf diese Weise können Sie vertrauliche Informationen bereinigen und verschiedene Sätze umgebungsspezifischer Werte für Test-, Staging- und Live-Zweige austauschen.
filter
dauertstdin
- es läuftsed
. Sie fangenstdin
in$GIT_INPUT
dann das zurück druckenstdout
über ein Rohrfilter
und seine fangenstdout
in$FILTERED_OUTPUT
und es dann drucken zurückstdout
. Alle 4 Zeilen am Ende Ihres obigen Beispiels könnten durch Folgendes ersetzt werden :filter
. Hier ist nichts für ungut gemeint, es ist nur ... du arbeitest zu hart. Sie brauchen die Shell-Variablen die meiste Zeit nicht - leiten Sie die Eingabe einfach an die richtige Stelle und geben Sie sie weiter.filter
, werden an den Enden von Eingabestreams, die ursprünglich nicht in Zeilenumbrüchen endeten, Zeilenumbrüche hinzugefügt. Eigentlich habe ich es nur getanfilter
, bin aber auf dieses Problem gestoßen, das mich zu dieser Lösung geführt hat, weil weder "immer neue Zeilen hinzufügen" noch "immer neue Zeilen entfernen" akzeptable Lösungen sind.sed
wird wahrscheinlich die zusätzliche Zeilenumbruch machen - aber Sie sollten dasfilter
nicht mit allen anderen erledigen . Und all diese Funktionen, die Sie haben, tun im Grunde das Gleiche - ased s///
. Sie verwenden die Shell, um Daten, die sie in ihrem Speicher gespeichert hatsed
,sed
weiterzuleiten, damit diese Daten möglicherweise durch andere Daten ersetzt werden, die die Shell in ihrem Speicher gespeichert hat, damitsed
sie an die Shell zurückgeleitet werden können. Warum nicht einfach[ "$var" = "$condition" ] && var=new_value
? Ich bekomme die Arrays auch nicht - speichern Sie den Array-Namen in und verwenden Sie ihn[0]
dannsed
, um ihn durch den Wert in zu ersetzen[1]
? Vielleicht chatten?filter
? Es funktioniert perfekt wie es ist. In Bezug darauf, wie der Code unter meinem Link funktioniert und warum ich ihn so eingerichtet habe, wie ich es getan habe, lassen Sie uns in einem Chatroom darüber sprechen.Antworten:
Die nachfolgenden Zeilenumbrüche werden entfernt, bevor der Wert in der Variablen gespeichert wird. Vielleicht möchten Sie etwas tun wie:
und verwenden
${var%x}
statt$var
. Zum Beispiel:Beachten Sie, dass dies das Problem der nachfolgenden Zeilenumbrüche löst, jedoch nicht das Null-Byte-Problem (wenn die Standardeingabe kein Text ist), da gemäß der POSIX-Befehlssubstitution :
Shell-Implementierungen können jedoch Null-Bytes beibehalten.
quelle
Sie können die
read
integrierte Funktion verwenden, um dies zu erreichen:Für ein Skript zum Lesen von STDIN wäre es einfach:
Ich bin mir nicht sicher, in welchen Shells das funktionieren wird. Funktioniert aber gut in Bash und Zsh.
quelle
-d
noch die Prozesssubstitution (<(...)
) sind portabel; Dieser Code funktioniertdash
beispielsweise nicht.-d
, das ist , warum ich den Haftungsausschluss unten setzen. Das OP gibt die Shell nicht an.dash
. Sie verwenden nur<<HEREDOC\n$(gen input)\nHEREDOC\n
- indash
- das Rohre für Heredocs genauso verwendet wie andere Shells sie für die Prozessersetzung - es macht keinen Unterschied. Dieread -d
Sache ist nur die Angabe eines Trennzeichens - Sie können das gleiche auf ein Dutzend Arten tun - seien Sie sich einfach sicher. Obwohl Sie etwas Schwanz brauchen werdengen input
.IFS=''
wohl nicht nötig. Es ist so gemeint, dassread
Leerzeichen nicht zusammenbrechen. Aber wenn es in eine einzelne Variable liest, hat es keine Auswirkung (an die ich mich erinnern kann). Aber ich fühle mich einfach sicherer, wenn ich es anlasse :-)Sie können wie folgt tun:
Was auch immer Sie tun,
$var
verschwindet, sobald Sie diese{ current shell ; }
Gruppierung verlassen. Es könnte aber auch so funktionieren:quelle
$var
in der{ ... }
Gruppierung, dies nicht immer möglich ist. Zum Beispiel, wenn dieser Befehl innerhalb einer Schleife ausgeführt wird und$var
außerhalb der Schleife benötigt wird.{}
Klammern .Es ist wahr - und in der Antwort ausdrücklich darauf hingewiesen wird - , dass der Wert für$var
ist sehr wahrscheinlich , ganz zu verschwinden , wenn die{ current shell; }
Gruppierung geschlossen. Gibt es eine explizitere Möglichkeit, es zu sagen als: Was auch immer Sie tun,$var
verschwindet ...?input | sed "s/'"'/&"&"&/g;s/.*/process2 '"'-> &'/" | sh
_variables
Funktion vonbash_completion
, die das Ergebnis einer Befehlsersetzung in einer globalen Variablen speichertCOMPREPLY
. Wenn eine Pipeline-Lösung zum Halten von Zeilenumbrüchen verwendet würde, würde das Ergebnis verloren gehen. In Ihrer Antwort hat man den Eindruck, dass beide Lösungen gleich gut sind. Darüber hinaus sollte beachtet werden, dass das Verhalten der Pipeline-Lösung stark von der Shell abhängt: Ein Benutzer könnteecho foo | { var=$(sed '$s/$/./'); var=${var%.}; } ; echo $var
mit ksh93 und zsh testen und denkt, dass dies in Ordnung ist, während dieser Code fehlerhaft ist.$var
verschwindet" (was eigentlich nicht stimmt, da dies von der Shell abhängt - das Verhalten wird von POSIX nicht spezifiziert), was ein eher neutraler Satz ist. Die zweite Lösung ist besser, da sie nicht unter diesem Problem leidet und ihr Verhalten in allen POSIX-Shells konsistent ist.