In diesem Dokument wird der Fehler "Unerwartetes Dateiende" angezeigt

81

Ich benötige mein Skript, um eine E-Mail vom Terminal zu senden. Basierend auf dem, was ich hier und an vielen anderen Orten online gesehen habe, habe ich es so formatiert:

/var/mail -s "$SUBJECT" "$EMAIL" << EOF
Here's a line of my message!
And here's another line!
Last line of the message here!
EOF

Wenn ich dies ausführe, erhalte ich jedoch folgende Warnung:

myfile.sh: line x: warning: here-document at line y delimited by end-of-file (wanted 'EOF')

myfile.sh: line x+1: syntax error: unexpected end of file

... wobei Zeile x die letzte geschriebene Codezeile im Programm ist und Zeile y die Zeile mit dem Code ist /var/mail. Ich habe versucht , zu ersetzen EOFmit anderen Dingen ( ENDOFMESSAGE, FINISHusw.) , aber ohne Erfolg. Fast alles, was ich online gefunden habe, hat es auf diese Weise gemacht, und ich bin wirklich neu bei Bash, daher fällt es mir schwer, es selbst herauszufinden. Könnte jemand Hilfe anbieten?

thnkwthprtls
quelle
9
Ist die EOFLinie eingerückt? Es muss am Anfang der Zeile stehen.
Barmar
Es ist, aber nur soweit diese gesamte Anweisung verschachtelt ist. Also muss es ganz links sein?
thnkwthprtls
2
Stellen Sie
2
Wenn Sie nur Tabulatorzeichen einrücken , können Sie <<-EOF- gnu.org/software/bash/manual/bashref.html#Here-Documents
Glenn Jackman

Antworten:

153

Das EOFToken muss sich am Anfang der Zeile befinden. Sie können es nicht zusammen mit dem dazugehörigen Codeblock einrücken.

Wenn Sie schreiben <<-EOF, können Sie es einrücken, aber es muss mit TabZeichen und nicht mit Leerzeichen eingerückt werden. Es könnte also auch mit dem Codeblock nicht enden.

Stellen Sie außerdem sicher, dass nach dem EOFToken in der Zeile kein Leerzeichen steht .

Barmar
quelle
2
Im obigen Codebeispiel befindet sich das EOF-Token am Anfang der Zeile.
Andrew Koster
Ich sehe es nicht im Bearbeitungsverlauf, aber es muss ursprünglich eingerückt worden sein, da ich nicht der einzige war, der auf dieses Problem hingewiesen hat.
Barmar
Ich erhalte diesen Fehler auch dann, wenn ich alle unnötigen Leerzeichen entferne.
Andrew Koster
Suchen Sie nach CR-Zeichen und dos2unixbeheben Sie diese.
Barmar
17

Die Zeile, die das Here-Doc beginnt oder beendet, enthält wahrscheinlich einige nicht druckbare Zeichen oder Leerzeichen (z. B. Wagenrücklauf), was bedeutet, dass das zweite "EOF" nicht mit dem ersten übereinstimmt und das Here-Doc nicht wie endet es sollte. Dies ist ein sehr häufiger Fehler, der nur mit einem Texteditor schwer zu erkennen ist. Sie können nicht druckbare Zeichen sichtbar machen, zum Beispiel mit cat:

cat -A myfile.sh

Sobald Sie die Ausgabe cat -Ader Lösung sehen, ist dies offensichtlich: Entfernen Sie die fehlerhaften Zeichen.

Joni
quelle
7

Bitte versuchen Sie, die vorhergehenden Leerzeichen zu entfernen, bevor Sie EOF: -

/var/mail -s "$SUBJECT" "$EMAIL" <<-EOF

Die Verwendung <tab>anstelle von <spaces>für ident UND die Verwendung von << - EOF funktioniert einwandfrei.

Das "-"entfernt das <tabs>nicht <spaces>, aber zumindest funktioniert das.

Rahul Tripathi
quelle
2
Der erste Vorschlag hilft nicht weiter (haben Sie getestet, ob Speicherplatz ein Problem verursacht?). Die zweite hilft nur, wenn die EOF-Zeile mit TAB eingerückt ist, nicht mit Leerzeichen.
Barmar
Ich denke, dass der abschließende Token keine führenden Leerzeichen haben darf
Rahul Tripathi
2

Beachten Sie, dass dieser Fehler auch auftreten kann, wenn Sie dies tun.

while read line; do
  echo $line
done << somefile

Da << somefilesollte < somefilein diesem Fall gelesen werden.

Roel Van de Paar
quelle
0

Hier ist eine flexible Möglichkeit, mit mehreren eingerückten Zeilen umzugehen, ohne heredoc zu verwenden.

  echo 'Hello!'
  sed -e 's:^\s*::' < <(echo '
    Some indented text here.
    Some indented text here.
  ')
  if [[ true ]]; then
    sed -e 's:^\s\{4,4\}::' < <(echo '
      Some indented text here.
        Some extra indented text here.
      Some indented text here.
    ')
  fi

Einige Hinweise zu dieser Lösung:

  • Wenn für den Inhalt einfache Anführungszeichen erwartet werden, können Sie diese entweder \mit Anführungszeichen oder durch doppelte Anführungszeichen ersetzen. Achten Sie im letzteren Fall darauf, dass die Konstruktion wie $(command)interpretiert wird. Wenn die Zeichenfolge sowohl einfache als auch doppelte Anführungszeichen enthält, müssen Sie zumindest der Art entkommen.
  • Im angegebenen Beispiel wird eine nachgestellte leere Zeile gedruckt. Es gibt zahlreiche Möglichkeiten, diese zu entfernen, die hier nicht enthalten sind, um den Vorschlag auf ein Minimum an Unordnung zu beschränken
  • Die Flexibilität ergibt sich aus der Leichtigkeit, mit der Sie steuern können, wie viel führender Platz bleiben oder gehen soll, vorausgesetzt, Sie kennen natürlich etwas sed REGEXP.
Psychosklave
quelle
0

Wenn ich Docstrings für meine Bash-Funktionen haben möchte , verwende ich eine Lösung ähnlich dem Vorschlag von user12205 in einem Duplikat dieser Frage.

Sehen Sie, wie ich USAGE für eine Lösung definiere, die:

  • Auto-Formate gut für mich in meiner IDE der Wahl (erhaben)
  • ist mehrzeilig
  • kann Leerzeichen oder Tabulatoren als Einrückung verwenden
  • behält Einrückungen innerhalb des Kommentars bei.
function foo {
    # Docstring
    read -r -d '' USAGE <<'    END'
        # This method prints foo to the terminal.
        #
        # Enter `foo -h` to see the docstring.
        #      It has indentations and multiple lines.
        #
        # Change the delimiter if you need hashtag for some reason.
        # This can include $$ and = and eval, but won't be evaluated
    END


    if [ "$1" = "-h" ]
    then
        echo "$USAGE" | cut -d "#" -f 2 | cut -c 2-
        return
    fi

    echo "foo"
}

So foo -hergibt sich:

This method prints foo to the terminal.

Enter `foo -h` to see the docstring.
     It has indentations and multiple lines.

Change the delimiter if you need hashtag for some reason.
This can include $$ and = and eval, but won't be evaluated

Erläuterung

cut -d "#" -f 2: Rufen Sie den zweiten Teil der #abgegrenzten Zeilen ab. (Denken Sie an eine CSV mit "#" als Trennzeichen, leere erste Spalte).

cut -c 2-: Rufen Sie das 2. bis Endzeichen der resultierenden Zeichenfolge ab

Beachten Sie auch, dass dies so if [ "$1" = "-h" ]ausgewertet wird, als Falsegäbe es kein erstes Argument ohne Fehler, da es sich um eine leere Zeichenfolge handelt.

Danisheater
quelle
-1

Zusammen mit den anderen Antworten von Barmar und Joni ist mir aufgefallen, dass ich bei der Verwendung manchmal vor und nach meinem EOF eine leere Zeile hinterlassen muss <<-EOF.

YOLO ROFL
quelle
1
Ich finde weder in der Theorie noch in der Praxis Unterstützung dafür. Downvoting als Aberglaube.
Tripleee
1
Ich hatte ein mehrzeiliges Here-Doc in Parens eingewickelt, um es umzuleiten, catund aufgrund der Formatierung musste ich kurz vor dem Schließen des Here-Doc-Markers vor dem schließenden Paren eine Eingabe hinzufügen, sonst würde ich diese Nichtübereinstimmung erhalten. Upvoting als vollständig gültig für "einige" Leute da draußen, wenn auch wahrscheinlich ein unwahrscheinliches Szenario.
SidOfc
Ich hasse es, zum Aberglauben beizutragen, aber ich hatte auch dieses Problem und fügte nach dem Ende meiner EOF eine leere Zeile hinzu. (Ubuntu 19.10 läuft im Docker; dies war in einem bootstrap.sh-Skript). Die leere Zeile hat diesen Fehler behoben.
NDP