Bash Fortsetzungslinien

158

Wie benutzt man Bash-Fortsetzungslinien?

Mir ist klar, dass Sie dies tun können:

echo "continuation \
lines"
>continuation lines

Wenn Sie jedoch Code eingerückt haben, funktioniert dies nicht so gut:

    echo "continuation \
    lines"
>continuation     lines
PyRulez
quelle
5
Der Bash Shell Style Guide von Google empfiehlt "hier" -Dokumente für "Wenn Sie Zeichenfolgen schreiben müssen, die länger als 80 Zeichen sind". Siehe @ Tripleees Antwort .
Trevor Boyd Smith
google.github.io/styleguide/… - Dies ist der direkte Link im neuen Dokument
jcollum

Antworten:

161

Dies ist, was Sie vielleicht wollen

$       echo "continuation"\
>       "lines"
continuation lines

Wenn dadurch zwei Argumente für das Echo erstellt werden und Sie nur eines möchten, sehen wir uns die Verkettung von Zeichenfolgen an. Wenn Sie in bash zwei Zeichenfolgen nebeneinander platzieren, verketten Sie:

$ echo "continuation""lines"
continuationlines

Eine Fortsetzungszeile ohne Einzug ist also eine Möglichkeit, eine Zeichenfolge aufzubrechen:

$ echo "continuation"\
> "lines"
continuationlines

Aber wenn ein Einzug verwendet wird:

$       echo "continuation"\
>       "lines"
continuation lines

Sie erhalten zwei Argumente, da dies keine Verkettung mehr ist.

Wenn Sie eine einzelne Zeichenfolge möchten, die Linien kreuzt, während Sie diese Leerzeichen einrücken, aber nicht erhalten, können Sie versuchen, die Fortsetzungslinie zu löschen und Variablen zu verwenden:

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

Auf diese Weise können Sie Code auf Kosten zusätzlicher Variablen sauber einrücken. Wenn Sie die Variablen lokalisieren, sollte dies nicht zu schlecht sein.

Ray Toal
quelle
1
Vielen Dank für Ihre Hilfe, aber während dies die Leerzeichen entfernt, sind sie jetzt separate Parameter (Bash interpretiert die Leerzeichen in der zweiten Zeile als Parametertrennzeichen) und werden jetzt nur aufgrund des Echo-Befehls korrekt gedruckt.
1
Oh, Sie möchten, dass eine einzelne (Bash-) Zeichenfolge Linien überspannt! Ich sehe jetzt.
Ray Toal
4
Lösung mit einer Variablen:s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
Johnny Thunderman
30

Hier eignen sich Dokumente mit dem <<-HERETerminator gut für eingerückte mehrzeilige Textzeichenfolgen. Es werden alle führenden Registerkarten aus dem Dokument hier entfernt. (Leitungsterminatoren bleiben jedoch weiterhin bestehen.)

cat <<-____HERE
    continuation
    lines
____HERE

Siehe auch http://ss64.com/bash/syntax-here.html

Wenn Sie einige, aber nicht alle führenden Leerzeichen beibehalten müssen, können Sie so etwas wie verwenden

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

oder vielleicht verwenden tr, um Zeilenumbrüche loszuwerden:

tr -d '\012' <<-____
    continuation
     lines
____

(Die zweite Zeile enthält eine Registerkarte und ein Leerzeichen vorne. Die Registerkarte wird vom Bindestrich-Operator vor dem Heredoc-Terminator entfernt, während das Leerzeichen erhalten bleibt.)

Um lange komplexe Zeichenfolgen über viele Zeilen zu wickeln, mag ich printf:

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

Es funktioniert auch gut in Kontexten, in denen Sie nicht triviale Teile des Shell-Skripts in eine andere Sprache einbetten möchten, in der Sie aufgrund der Syntax der Host-Sprache kein Here-Dokument verwenden können, z. B. in einem Makefileoder Dockerfile.

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript
Tripleee
quelle
Funktioniert bei mir nicht Ubuntu 16.04. Ich bekomme zwei Zeilen anstelle der erwarteten verketteten eine Zeile.
Penghe Geng
@PengheGeng In der Tat löst dies das Problem, Einrückungen zu beseitigen und nicht Linien miteinander zu verbinden. Sie können die neue Zeile am Ende einer Zeile weiterhin rückwärts streichen, um zwei Zeilen miteinander zu verbinden.
Tripleee
(Aber sehen Sie das erste printfBeispiel auch jetzt.)
Tripleee
12

Sie können Bash-Arrays verwenden

$ str_array=("continuation"
             "lines")

dann

$ echo "${str_array[*]}"
continuation lines

Es gibt einen zusätzlichen Platz, weil (nach dem Bash-Handbuch):

Wenn das Wort in doppelte Anführungszeichen gesetzt ist, wird es ${name[*]}zu einem einzelnen Wort erweitert, wobei der Wert jedes Array-Elements durch das erste Zeichen der IFS-Variablen getrennt ist

So setzt IFS=''mehr Platz , um loszuwerden ,

$ IFS=''
$ echo "${str_array[*]}"
continuationlines
tworec
quelle
4

In bestimmten Szenarien kann es sinnvoll sein, die Verkettungsfähigkeit von Bash zu nutzen.

Beispiel:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

Aus dem Abschnitt PARAMETER der Bash Man-Seite:

name = [Wert] ...

... In dem Kontext, in dem eine Zuweisungsanweisung einer Shell-Variablen oder einem Array-Index einen Wert zuweist, kann der Operator + = verwendet werden, um den vorherigen Wert der Variablen anzuhängen oder zu ergänzen. Wenn + = auf eine Variable angewendet wird, für die das Integer-Attribut festgelegt wurde, wird der Wert als arithmetischer Ausdruck ausgewertet und zum aktuellen Wert der Variablen hinzugefügt, der ebenfalls ausgewertet wird. Wenn + = mithilfe der zusammengesetzten Zuweisung auf eine Array-Variable angewendet wird (siehe Arrays unten), wird der Wert der Variablen nicht aufgehoben (wie bei Verwendung von =), und neue Werte werden an das Array angehängt, beginnend mit einem Wert, der größer als der maximale Index des Arrays ist (für indizierte Arrays) oder als zusätzliche Schlüssel-Wert-Paare in einem assoziativen Array hinzugefügt. Bei Anwendung auf eine Variable mit Zeichenfolgenwert wird der Wert erweitert und an den Wert der Variablen angehängt.

Cybernaut
quelle
Wahrscheinlich der beste Rat auf dieser Seite. Die Verwendung eines HEREDOC und das Piping in eine Übersetzung für <CR> s ist sehr unintuitiv und schlägt fehl, wenn die Zeichenfolge tatsächlich diskret platzierte Zeilentrennzeichen haben muss.
Ingyhere
2

Ich stieß auf eine Situation, in der ich als Teil eines Befehlsarguments eine lange Nachricht senden und die Zeilenlängenbeschränkung einhalten musste. Die Befehle sehen ungefähr so ​​aus:

somecommand --message="I am a long message" args

Die Art und Weise, wie ich dies gelöst habe, besteht darin, die Nachricht als hier-Dokument zu verschieben (wie von @tripleee vorgeschlagen). Aber ein hier-Dokument wird zu einem Standard, daher muss es wieder eingelesen werden. Ich habe den folgenden Ansatz gewählt:

message=$(
    tr "\n" " " <<- END
        This is a
        long message
END
)
somecommand --message="$message" args

Dies hat den Vorteil, dass $messagegenau wie die Zeichenfolgenkonstante ohne zusätzliche Leerzeichen oder Zeilenumbrüche verwendet werden kann.

Beachten Sie, dass den tatsächlichen obigen Nachrichtenzeilen tabjeweils ein Zeichen vorangestellt ist , das von diesem Dokument selbst entfernt wird (aufgrund der Verwendung von <<-). Am Ende befinden sich noch Zeilenumbrüche, die dann durch ddLeerzeichen ersetzt werden.

Beachten Sie auch, dass, wenn Sie keine Zeilenumbrüche entfernen, diese unverändert angezeigt werden, wenn sie "$message"erweitert werden. In einigen Fällen können Sie das Problem möglicherweise umgehen, indem Sie die doppelten Anführungszeichen entfernen. $messageDie Nachricht ist jedoch kein einzelnes Argument mehr.

haridsv
quelle
2

Zeilenfortsetzungen können auch durch geschickte Verwendung der Syntax erreicht werden.

Im Fall von echo:

# echo '-n' flag prevents trailing <CR> 
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.

Im Fall von Vars:

outp="This is my one-line statement" ; 
outp+=" that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

Ein anderer Ansatz bei Vars:

outp="This is my one-line statement" ; 
outp="${outp} that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

Voila!

ingyhere
quelle
1

Sie können es einfach wie in der Einrückung wie folgt mit Zeilenumbrüchen (ohne Backslash) trennen und einfach neue Zeilen entfernen.

Beispiel:

echo "continuation
of 
lines" | tr '\n' ' '

Wenn es sich um eine variable Definition handelt, werden Zeilenumbrüche automatisch in Leerzeichen konvertiert. Entfernen Sie daher nur zusätzliche Leerzeichen, falls zutreffend.

x="continuation
of multiple
lines"
y="red|blue|
green|yellow"

echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case
rjni
quelle
1

Dies ist nicht genau das, was der Benutzer gefragt hat, aber eine andere Möglichkeit, eine lange Zeichenfolge zu erstellen, die mehrere Zeilen umfasst, besteht darin, sie schrittweise aufzubauen, wie folgt:

$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World

In diesem Fall wäre es natürlich einfacher gewesen, es auf einmal zu erstellen, aber dieser Stil kann bei längeren Saiten sehr leicht und verständlich sein.

Jon McClung
quelle
0

Wenn Sie jedoch Code eingerückt haben, funktioniert dies nicht so gut:

    echo "continuation \
    lines"
>continuation     lines

Versuchen Sie es mit einfachen Anführungszeichen und verketten Sie die Zeichenfolgen:

    echo 'continuation' \
    'lines'
>continuation lines

Hinweis: Die Verkettung enthält ein Leerzeichen.

mMontu
quelle
2
Es funktioniert mit Echo- und String-Argumenten, aber nicht mit anderen Dingen wie der Variablenzuweisung. Obwohl es nicht um Variablen ging, war die Verwendung von Echo nur ein Beispiel. Anstatt echo wenn Sie hätten x=, würden Sie die Fehlermeldung erhalten : lines: command not found.
LS
0

Abhängig davon, welche Art von Risiken Sie akzeptieren und wie gut Sie die Daten kennen und ihnen vertrauen, können Sie eine vereinfachte Variableninterpolation verwenden.

$: x="
    this
    is
       variably indented
    stuff
   "
$: echo "$x" # preserves the newlines and spacing

    this
    is
       variably indented
    stuff

$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff
Paul Hodges
quelle
-2

Dies beantwortet Ihre Frage wahrscheinlich nicht wirklich, aber Sie finden sie möglicherweise trotzdem nützlich.

Der erste Befehl erstellt das Skript, das vom zweiten Befehl angezeigt wird.

Der dritte Befehl macht dieses Skript ausführbar.

Der vierte Befehl enthält ein Verwendungsbeispiel.

john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent 
#!/usr/bin/env python
import textwrap, sys

def bash_dedent(text):
    """Dedent all but the first line in the passed `text`."""
    try:
        first, rest = text.split("\n", 1)
        return "\n".join([first, textwrap.dedent(rest)])
    except ValueError:
        return text  # single-line string

print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
>     second line
>     third line")"
first line
second line
third line

Beachten Sie, dass es sinnvoller ist, das ausführbare Skript ~/binso zu verschieben, dass es sich in Ihrem Pfad befindet , wenn Sie dieses Skript wirklich verwenden möchten .

Überprüfen Sie die Python-Referenz auf Details zur Funktionsweise textwrap.dedent.

Wenn die Verwendung von $'...'oder "$(...)"für Sie verwirrend ist, stellen Sie eine andere Frage (eine pro Konstrukt), falls noch keine vorhanden ist. Es kann hilfreich sein, einen Link zu der Frage bereitzustellen, die Sie finden / stellen, damit andere Personen eine verknüpfte Referenz haben.

intuitiv
quelle
6
Gut gemeint - und möglicherweise sogar nützlich -, obwohl dies sein mag, bat das OP um Rat zur grundlegenden Bash-Syntax, und Sie gaben ihm eine Python-Funktionsdefinition, die OO-Paradigmen, außergewöhnliche Flusskontrolle und Importe verwendet. Außerdem haben Sie eine ausführbare Datei als Teil einer Zeichenfolgeninterpolation aufgerufen - etwas, das eine Person, die diese Art von Frage stellt, in bash definitiv noch nicht gesehen hätte.
Parthian Shot