Ich versuche, HEREDOC-Text auf POSIX-kompatible Weise in eine Shell-Skriptvariable zu bringen. Ich habe es so versucht:
#!/bin/sh
NEWLINE="
"
read_heredoc2() {
while IFS="$NEWLINE" read -r read_heredoc_line; do
echo "${read_heredoc_line}"
done
}
read_heredoc2_result="$(read_heredoc2 <<'HEREDOC'
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
HEREDOC
)"
echo "${read_heredoc2_result}"
Das ergab Folgendes, was falsch ist:
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ | | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
Folgendes funktioniert, aber ich mag es nicht, wie klobig es ist, eine zufällige Ausgabevariable zu verwenden:
#!/bin/sh
NEWLINE="
"
read_heredoc1() {
read_heredoc_first=1
read_heredoc_result=""
while IFS="$NEWLINE" read -r read_heredoc_line; do
if [ ${read_heredoc_first} -eq 1 ]; then
read_heredoc_result="${read_heredoc_line}"
read_heredoc_first=0
else
read_heredoc_result="${read_heredoc_result}${NEWLINE}${read_heredoc_line}"
fi
done
}
read_heredoc1 <<'HEREDOC'
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
HEREDOC
echo "${read_heredoc_result}"
Richtige Ausgabe:
_ _ _
| | | (_)
_ __ ___ _ _ _ __ | | __ _ ___ ___ ___ _ __ | |_ _ __ ___
| '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
| | | | | | |_| | |_) | | (_| | (_| __/ (_) | | | | | | | | | __/
|_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
__/ | |
|___/|_|
Irgendwelche Ideen?
shell-script
posix
Kevin
quelle
quelle
cat
direkt mit einem Here-Dokument. Wenn es an vielen Stellen im Skript verwendet wird, speichern Sie es in einer Dateicat
und von dort aus, genau wie/etc/motd
es auf einigen Systemen verwendet wird.ksh
,dash
,ash
, und die älteste Bourne - Shell ich finden kann. Das Parsen von Bash-Befehlssubstitutionen ist seltsam und war früher noch fehlerhafter.)
und die zitierten Heredocs keine Erweiterungen mehr haben.Antworten:
Das Problem ist, dass in Bash Inside-
$( ... )
Escape-Sequenzen (und andere) analysiert werden, obwohl der Heredoc sie selbst nicht haben würde. Sie erhalten eine doppelte Linie, weil\
der Zeilenumbruch entgeht. Was Sie sehen, ist wirklich ein Analyseproblem in Bash - andere Shells tun dies nicht. Backticks können auch in älteren Versionen ein Problem sein. Ich habe bestätigt, dass dies ein Fehler in Bash ist und in zukünftigen Versionen behoben wird.Sie können Ihre Funktion zumindest drastisch vereinfachen:
Wenn Sie die Ausgangsvariable auswählen möchten, kann diese parametriert werden:
Oder eine ziemlich hässliche ohne
eval
:Die
{}
werden eher benötigt als()
, damit die Variable danach verfügbar bleibt.Je nachdem, wie oft und zu welchem Zweck Sie dies tun, bevorzugen Sie möglicherweise die eine oder andere dieser Optionen. Der letzte ist der prägnanteste für eine einmalige.
Wenn Sie in der Lage sind, zu verwenden
zsh
, funktioniert Ihre ursprüngliche Befehlsersetzung + heredoc wie sie ist, aber Sie können all dies auch weiter unten reduzieren:Bash unterstützt dies nicht und ich glaube auch nicht, dass eine andere Shell, bei der das Problem auftritt, dies tut.
quelle
$(cat)
finde , ist das Entfernen von nachgestellten ZeilenumbrüchenÜber die OP-Lösung:
Sie benötigen keine Auswertung, um eine Variable zuzuweisen, wenn Sie die Verwendung einer konstanten Variablen zulassen.
Die allgemeine Struktur des Aufrufs einer Funktion, die das HEREDOC empfängt, könnte ebenfalls implementiert werden.
Eine Lösung, die in allen (vernünftigen) Schalen mit beiden gelösten Elementen funktioniert, ist folgende:
Eine Lösung für die ursprüngliche Frage.
Eine Lösung, die seit Bash 2.04 (und den neuesten Versionen zsh, lksh, mksh) funktioniert.
Unten finden Sie eine portablere Version (POSIX).
Der Kernbefehl
funktioniert wie folgt:
HEREDOC
wird (einfach) in Anführungszeichen gesetzt, um eine Erweiterung des folgenden Textes zu vermeiden.<<
.-d ''
zwingtread
dazu, den gesamten Inhalt des "here doc" zu schlürfen.-r
Option vermeidet die Interpretation von Zeichen mit Backslash-Anführungszeichen.read var
.IFS=''
, dass vermieden wird, dass beim Lesen führende oder nachfolgende Zeichen im Standard-IFS entfernt werden : spacetabnewline.In ksh
-d ''
funktioniert der Nullwert für die Option nicht.Als Problemumgehung
-d $'\r'
funktioniert a, wenn der Text keinen "Wagenrücklauf" enthält (wenn$'\r'
am Ende jeder Zeile natürlich a hinzugefügt wird).Eine zusätzliche Anforderung (in Kommentaren) besteht darin, eine POSIX-kompatible Lösung zu generieren.
POSIX
Erweiterung der Idee, damit sie nur mit POSIX-Optionen ausgeführt wird.
Das heißt vor allem nein
-d
fürread
. Das erzwingt einen Lesevorgang für jede Zeile.Dies erzwingt wiederum die Notwendigkeit, jeweils eine Linie zu erfassen.
Um
var
eine nachfolgende neue Zeile zu erstellen, muss diese hinzugefügt werden (da der Lesevorgang sie entfernt hat).Das funktioniert (und wurde getestet) in allen vernünftigen Schalen.
quelle
Nutzloser Gebrauch von Katze (Zitat \ und `):
Oder ohne zu zitieren:
quelle
Um nachfolgende Zeilenumbrüche zu unterstützen, habe ich die Antwort von @MichaelHomer mit meiner ursprünglichen Lösung kombiniert. Ich habe die vorgeschlagenen Problemumgehungen aus dem von @EliahKagan angegebenen Link nicht verwendet, da der erste magische Zeichenfolgen verwendet und die letzten beiden nicht POSIX-kompatibel waren.
quelle
eval
wird es nur für den Namen der "Ausgabevariablen" verwendet. Wenn wir von vertrauenswürdigen Benutzern der Funktion ausgehen, gibt eseval
in diesem Beispiel weitere Probleme ?text
Zeile muss mit einer neuen Zeile enden". Suchen Sie in Definitionen der Textdatei.