tutaj-dokument wyświetla błąd „nieoczekiwany koniec pliku”


82

Potrzebuję mojego skryptu, aby wysłać wiadomość e-mail z terminala. Opierając się na tym, co widziałem tutaj i wielu innych miejscach online, sformatowałem to w następujący sposób:

/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

Jednak gdy to uruchomię, otrzymuję to ostrzeżenie:

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

... gdzie linia x to ostatnia zapisana linia kodu w programie, a linia y to linia, /var/mailw której się znajduje. Próbowałem wymianie EOFz innymi ( ENDOFMESSAGE, FINISH, itd.), Ale bezskutecznie. Prawie wszystko, co znalazłem w Internecie, działa w ten sposób, a ja jestem naprawdę nowy w bash, więc ciężko mi to rozgryźć samodzielnie. Czy ktoś mógłby zaoferować pomoc?


9
Czy EOFwiersz jest wcięty? Musi być na początku linii.
— Barmar

Tak jest, ale tylko w przypadku zagnieżdżenia całej instrukcji. Więc to musi być cała na lewo?
— thnkwthprtls

2
Upewnij się również, że nie ma znaków końcowych (w tym powrotu karetki!)
— glenn jackman

2
Jeśli wcinasz tylko za pomocą znaków tabulacji, możesz użyć <<-EOF- gnu.org/software/bash/manual/bashref.html#Here-Documents
— glenn jackman

Odpowiedzi:


157

EOFŻeton musi być na początku linii, nie można wciąć go wraz z blokiem kodu to idzie z.

Jeśli piszesz <<-EOF, możesz wciąć go, ale musi być wcięty za pomocą Tabznaków, a nie spacji. Więc nadal może nie skończyć się nawet z blokiem kodu.

Również upewnić się, że nie ma spacji poEOF żeton na linii.


2
W powyższym przykładzie kodu token EOF znajduje się na początku wiersza.
— Andrew Koster

Nie widzę tego w historii edycji, ale musiało być pierwotnie wcięte, ponieważ nie tylko ja wskazałem na ten problem.
— Barmar

Ten błąd pojawia się nawet wtedy, gdy usuwam wszystkie niepotrzebne spacje.
— Andrew Koster

Sprawdź znaki CR i użyj, dos2unixaby to naprawić.
— Barmar

17

Linia, która zaczyna lub kończy dokument tutaj, prawdopodobnie zawiera jakieś niedrukowalne lub białe znaki (na przykład powrót karetki), co oznacza, że ​​drugi „EOF” nie pasuje do pierwszego i nie kończy dokumentu tutaj, jak powinno. Jest to bardzo częsty błąd i trudny do wykrycia za pomocą samego edytora tekstu. Możesz sprawić, że znaki niedrukowalne będą widoczne, na przykład za pomocą cat:

cat -A myfile.sh

Gdy zobaczysz wyjście z cat -Arozwiązania, będzie oczywiste: usuń obraźliwe znaki.


7

Spróbuj usunąć poprzedzające spacje przed EOF: -

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

Używanie <tab>zamiast <spaces>ident AND używanie << - EOF działa dobrze.

"-"Usuwa <tabs>, nie <spaces>, ale przynajmniej to działa.


2
Pierwsza sugestia nie pomoże (czy przetestowałeś, czy przestrzeń powoduje problem?). Drugi pomoże tylko wtedy, gdy wiersz EOF jest wcięty za pomocą TAB, a nie spacji.
— Barmar

Myślę, że żeton kończący nie może mieć wiodących spacji
— Rahul Tripathi,

2

Zauważ, że możesz również otrzymać ten błąd, jeśli to zrobisz;

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

Bo << somefilepowinienem przeczytać < somefilew tym przypadku.


0

Oto elastyczny sposób radzenia sobie z wieloma wierszami z wcięciem bez użycia heredoc.

  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

Kilka uwag na temat tego rozwiązania:

  • jeśli oczekuje się, że treść będzie zawierała proste cudzysłowy, \zastąp je znakami cudzysłowu lub zastąp je podwójnymi cudzysłowami. W tym drugim przypadku należy uważać, aby podobna konstrukcja $(command)została zinterpretowana. Jeśli ciąg zawiera zarówno cudzysłowy proste, jak i cudzysłowy, musisz przynajmniej uciec.
  • podany przykład wypisuje końcową pustą linię, istnieje wiele sposobów na pozbycie się go, nieuwzględnione tutaj, aby ograniczyć do minimum bałagan w propozycji
  • elastyczność wynika z łatwości, z jaką możesz kontrolować, ile miejsca na prowadzenie powinno pozostać lub zniknąć, pod warunkiem, że znasz oczywiście sedno REGEXP.

0

Kiedy chcę mieć ciągi dokumentacyjne dla moich funkcji bash, używam rozwiązania podobnego do sugestii user12205 w duplikacie tego pytania.

Zobacz, jak definiuję USAGE dla rozwiązania, które:

  • automatyczne formatowanie dobrze dla mnie w moim wybranym IDE (wysublimowane)
  • jest wieloliniowy
  • może używać spacji lub tabulatorów jako wcięć
  • zachowuje wcięcia w komentarzu.
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"
}

Więc foo -hdaje:

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

Wyjaśnienie

cut -d "#" -f 2: Pobierz drugą część #rozdzielonych linii. (Pomyśl o csv z „#” jako separatorem, pustą pierwszą kolumnę).

cut -c 2-: Pobierz drugi do końca znak wynikowego ciągu

Zauważ również, że if [ "$1" = "-h" ]obliczane jest tak, Falsejakby nie było pierwszego argumentu, bez błędu, ponieważ staje się pustym ciągiem.


-1

Wraz z innymi odpowiedziami wymienionymi przez Barmara i Joni zauważyłem, że czasami muszę zostawić pustą linię przed i po moim EOF podczas używania <<-EOF.


1
Nie znajduję na to poparcia ani w teorii, ani w praktyce. Głosowanie za przesądem.
— tripleee

1
Miałem multilinię here-doc zawiniętą w pareny do przekierowania cati ze względu na formatowanie, tuż przed moim zamykającym znacznikiem here-doc, musiałem dodać enter przed zamykającym parenem, w przeciwnym razie dostałbym tę niezgodność. Głosowanie za głosami jest całkowicie ważne dla „niektórych” ludzi, choć prawdopodobnie jest to mało prawdopodobny scenariusz.
— SidOfc

Nienawidzę przyczyniać się do przesądów, ale miałem też ten problem i dodałem pustą linię po zakończeniu mojego EOF. (ubuntu 19.10 działający w dockerze; to było w skrypcie bootstrap.sh). Pusta linia naprawiła ten błąd.
— NDP
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.