Wie gebe ich eine mehrzeilige Zeichenfolge in Bash aus?

250

Wie kann ich eine Multipline-Zeichenfolge in Bash ausgeben, ohne mehrere Echoaufrufe wie folgt zu verwenden:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

Ich suche nach einer tragbaren Möglichkeit, dies zu tun, indem ich nur Bash-Builtins verwende.

Hilfsmethode
quelle
4
Wenn Sie eine Verwendungsnachricht als Antwort auf einen falschen Aufruf ausgeben, senden Sie diese Nachricht normalerweise an einen Standardfehler anstelle einer Standardausgabe mitecho >&2 ...
Mark Reed,
2
@MarkReed Die Verwendungsnachricht wird durch Eingabe ausgegeben --help(die zum Standardausgang gehen sollte).
Hilfsmethode
Für andere, die mitkommen, sind weitere Informationen zu "hier Dokumente" verfügbar: tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez
Überprüfen Sie die printfbasierte Lösung von Gordon Davidson. Obwohl es im Schatten der echooder der catbasierten Ansätze steht, scheint es viel weniger ein Kludge zu sein. Zugegeben, die "printf" -Syntax stellt eine
gewisse
Siehe auch
Anton Tarasenko

Antworten:

296

Hier werden häufig Dokumente zu diesem Zweck verwendet.

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

Sie werden in allen von Bourne abgeleiteten Shells unterstützt, einschließlich aller Versionen von Bash.

Bis auf weiteres angehalten.
quelle
4
Ja - ist aber catnicht eingebaut.
Mark Reed
8
@ MarkReed: Das stimmt, ist aber immer verfügbar (außer möglicherweise unter ungewöhnlichen Umständen).
Bis auf weiteres angehalten.
6
+1 Thx. Am Ende habe ich read -d '' help <<- EOF ...den mehrzeiligen String in eine Variable eingelesen und dann das Ergebnis wiedergegeben.
Hilfsmethode
3
Kann ich ein HEREDOC in einer Variablen speichern?
Chovy
177

oder Sie können dies tun:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "
Chris Mohr
quelle
1
@OliverWeiler: Es funktioniert sogar in Bourne-Shells wie Dash und der Heirloom Bourne-Shell .
Bis auf weiteres angehalten.
6
Nicht großartig, wenn Sie dies in einer Funktion benötigen, da Sie entweder 1) die Zeichenfolge ganz links von Ihrer Datei verschieben müssen oder 2) sie eingerückt lassen müssen, um mit dem Rest Ihres Codes übereinzustimmen, aber dann druckt sie mit die Einrückungen auch
sg
43

Inspiriert von den aufschlussreichen Antworten auf dieser Seite habe ich einen gemischten Ansatz entwickelt, den ich für den einfachsten und flexibleren halte. Was denken Sie?

Zunächst definiere ich die Verwendung in einer Variablen, sodass ich sie in verschiedenen Kontexten wiederverwenden kann. Das Format ist sehr einfach, fast WYSIWYG, ohne dass Steuerzeichen hinzugefügt werden müssen. Dies scheint mir ziemlich portabel zu sein (ich habe es unter MacOS und Ubuntu ausgeführt)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

Dann kann ich es einfach als verwenden

echo "$__usage"

oder noch besser, wenn ich Parameter analysiere, kann ich es dort einfach in einem Einzeiler wiedergeben:

levelN=${2:?"--level: n is required!""${__usage}"}
Jorge
quelle
4
Dies funktionierte für mich in einem Skript, in dem die obige Antwort nicht funktioniert (ohne Änderung).
David Welch
3
Dies ist viel sauberer, als eine Reihe von Zeichen wie \ t und \ n
sg
1
Aus bestimmten Gründen wird für mich alles in derselben Zeile gedruckt: /
Nicolas de Fontenay
2
@Nicolas: echo "$__usage"Für mich war es notwendig, doppelte Anführungszeichen zu verwenden . echo $__usagefunktioniert nicht.
Mario
24

Verwenden Sie die -eOption, dann können Sie ein neues Zeilenzeichen mit \nin der Zeichenfolge drucken .

Probe (aber nicht sicher, ob eine gute oder nicht)

Das Schöne ist, dass diese -eOption nicht in der Manpage von MacOS dokumentiert ist, solange sie noch verwendet werden kann. Es ist in der Manpage von Linux dokumentiert .

nhahtdh
quelle
6
Diese Manpages sind für den vom System bereitgestellten echoBefehl vorgesehen /bin/echo, für den unter Mac OS keine -eOption verfügbar ist . Wenn Sie Bash auf diesen Systemen verwenden, echoübernimmt der integrierte Befehl. Sie können dies sehen, indem Sie /bin/echo whateverden Unterschied im Verhalten explizit eingeben und beobachten. Geben Sie Folgendes ein, um die Dokumentation für das integrierte Gerät anzuzeigen help echo.
Mark Reed
1
/bin/echounterscheidet sich oft von Betriebssystem zu Betriebssystem und von Bashs integriertem Betriebssystem echo.
Bis auf weiteres angehalten.
@ MarkReed: Ich werde es später versuchen, aber danke für die Info. +1. Ich werde hier nur meine Antwort hinterlassen, da viele gute Diskussionen stattfinden.
nhahtdh
7
echo -eist nicht portierbar - einige Echo-Implementierungen geben beispielsweise das "-e" als Teil der Ausgabe aus. Wenn Sie Portabilität wünschen, verwenden Sie stattdessen printf. Dies tut beispielsweise / bin / echo unter OS X 10.7.4. IIRC das eingebaute Bash-Echo war auch unter 10.5.0 seltsam, aber ich erinnere mich nicht mehr an die Details.
Gordon Davisson
2
echo -ehat mich schon mal gebissen ... Auf jeden Fall benutzen printfoder catmit einem Heredoc. Die <<-Variante dieser Dokumente ist besonders schön, da Sie führende Einrückungen in der Ausgabe
entfernen können
22

Da ich printfin einem Kommentar empfohlen habe , sollte ich wahrscheinlich einige Beispiele für seine Verwendung nennen (obwohl ich zum Drucken einer Verwendungsnachricht eher Dennis 'oder Chris' Antworten verwenden würde). printfist etwas komplexer zu bedienen als echo. Das erste Argument ist eine Formatzeichenfolge, in der Escapezeichen (wie \n) immer interpretiert werden. Es kann auch Formatanweisungen enthalten %, die damit beginnen , welche und wo zusätzliche Argumente darin enthalten sind. Hier sind zwei verschiedene Ansätze, um es für eine Verwendungsnachricht zu verwenden:

Zunächst können Sie die gesamte Nachricht in die Formatzeichenfolge aufnehmen:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

Beachten Sie, dass Sie im Gegensatz echodazu die letzte neue Zeile explizit einfügen müssen. Wenn die Nachricht %Zeichen enthält, müssen diese als geschrieben werden %%. Wenn Sie die Fehlerbericht- und Homepage-Adressen angeben möchten, können diese ganz natürlich hinzugefügt werden:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

Zweitens können Sie einfach die Formatzeichenfolge verwenden, um jedes zusätzliche Argument in einer separaten Zeile zu drucken:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

Mit dieser Option ist das Hinzufügen der Bugreport- und Homepage-Adressen ziemlich offensichtlich:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"
Gordon Davisson
quelle
9

Auch mit eingerücktem Quellcode können Sie <<-(mit einem nachgestellten Bindestrich) führende Tabulatoren (aber keine führenden Leerzeichen) ignorieren. Zum Beispiel dies:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

Gibt eingerückten Text ohne das führende Leerzeichen aus:

line1
line2
Elliptische Ansicht
quelle
Das hat bei mir nicht funktioniert. Welche Shell benutzt du?
Four43
Hat in Bash 4.4.19 in Ubuntu nicht funktioniert. Der Abstand vor Zeile
1
1
@ four43, du hattest recht. Funktioniert nicht, um führende Leerzeichen zu entfernen. Entfernt jedoch führende Registerkarten. Also habe ich meine Antwort von Tabulatoren und Leerzeichen zu Tabulatoren und nicht zu Leerzeichen korrigiert. Entschuldige mich für den Fehler. Ich habe das Handbuch überprüft und es steht eindeutig nur, dass die Registerkarten entfernt wurden. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben.
Elliptische Ansicht
0

Wenn Sie die Lösung von @jorge verwenden und feststellen, dass sich alles in derselben Zeile befindet, stellen Sie sicher, dass Sie die Variable in Anführungszeichen setzen:

echo $__usage

druckt alles in einer Zeile während

echo "$__usage"

behält die Zeilenumbrüche bei.

user1165471
quelle
Dies ist eigentlich die einzige Lösung, die für mich funktioniert hat. Printf macht viele Dinge und mit meiner mehrzeiligen XML erfordert es wahrscheinlich viel Flucht, weil es den Inhalt vollständig entstellt. Ich cat <<EOF .... EOF
weise