тут-документ видає помилку "несподіваний кінець файлу"


82

Мені потрібен мій сценарій для надсилання електронного листа з терміналу. На основі того, що я бачив тут та багатьох інших місцях в Інтернеті, я відформатував це так:

/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

Однак, коли я запускаю це, я отримую таке попередження:

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

... де рядок x - останній записаний рядок коду в програмі, а рядок y - рядок, що міститься /var/mailв ньому. Я спробував замінити EOFз іншими речами ( ENDOFMESSAGE, FINISHі т.д.) , але безрезультатно. Майже все, що я знайшов в Інтернеті, це робилося таким чином, і я справді новачок у bash, тому мені важко зрозуміти це самостійно. Хтось може запропонувати будь-яку допомогу?


9
Чи є EOFвідступ лінії? Це має бути на початку рядка.
Barmar

Це так, але лише наскільки вкладено весь цей оператор. Отже, це повинно бути аж ліворуч?
thnkwthprtls

2
Крім того, переконайтеся, що відсутні кінцеві символи (включаючи повернення каретки!)
glenn jackman

2
Якщо ви робите відступ лише символами табуляції, ви можете використовувати <<-EOF- gnu.org/software/bash/manual/bashref.html#Here-Documents
glenn jackman

Відповіді:


156

EOFМаркер повинен бути на початку рядка, ви не можете відступ його разом з блоком коду вона йде с.

Якщо ви пишете, <<-EOFви можете зробити його відступом, але він повинен бути з відступами Tabсимволами, а не пробілами. Тож це все одно може не закінчитися навіть із блоком коду.

Також переконайтеся , що ви маєте ніяких прогалин післяEOF маркера на лінії.


2
У наведеному вище прикладі коду маркер EOF знаходиться на початку рядка.
Ендрю Костер

Я не бачу цього в історії редагування, але він, мабуть, спочатку був з відступами, тому що я не єдиний вказував на цю проблему.
Бармар

Я отримую цю помилку, навіть коли видаляю всі непотрібні пробіли.
Ендрю Костер

Перевірте наявність символів CR та використовуйте dos2unixдля їх виправлення.
Бармар

17

Рядок, який починається або закінчується тут-документом, можливо, має якісь недруковані або пробіли (наприклад, повернення каретки), що означає, що другий "EOF" не збігається з першим і не закінчується тут-документом, як це повинно. Це дуже поширена помилка, яку важко виявити лише за допомогою текстового редактора. Ви можете зробити недруковані символи видимими, наприклад, за допомогою cat:

cat -A myfile.sh

Як тільки ви побачите результат з cat -Aрішення, буде очевидним: видаліть образливі символи.


7

Будь ласка, спробуйте видалити попередні пробіли перед EOF: -

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

Використання <tab>замість <spaces>для ident І використання << - EOF відмінно працює.

"-"Видаляє <tabs>, а НЕ <spaces>, але принаймні це працює.


2
Перша пропозиція не допоможе (ви протестували, чи не викликає простір проблема?). Другий допоможе лише в тому випадку, якщо рядок EOF має відступ TAB, а не пробіли.
Barmar

Я думаю, що кінцевий маркер не повинен мати пробілів
Рахул Тріпаті

2

Зверніть увагу, що ви також можете отримати цю помилку, якщо ви це зробите;

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

Тому що << somefileчитати слід < somefileу цьому випадку.


0

Ось гнучкий спосіб впоратися з кількома відступними рядками без використання 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

Деякі примітки щодо цього рішення:

  • якщо у вмісті передбачаються прості лапки, або уникайте їх, використовуючи, \або замініть роздільники рядків на подвійні лапки. В останньому випадку будьте обережні, щоб конструкція типу $(command)інтерпретувалася. Якщо рядок містить як прості, так і подвійні лапки, вам доведеться уникати хоча б виду.
  • у наведеному прикладі надрукуйте кінцевий порожній рядок, існує безліч способів позбутися цього, не включені сюди, щоб звести пропозицію до мінімуму
  • гнучкість походить від легкості, з якою ви можете контролювати, скільки провідного простору має залишатися чи йти, за умови, що ви, звичайно, знаєте деякий sed REGEXP.

0

Коли я хочу , щоб мати рядки документації для виконання своїх функцій Баш, я використовую рішення , схоже на пропозицію user12205 в двох примірниках цього питання.

Подивіться, як я визначаю USAGE для рішення, яке:

  • автоматичні формати для мене в обраній IDE (на вищому рівні)
  • є багаторядковою
  • може використовувати пробіли або вкладки як відступ
  • зберігає відступи у коментарі.
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"
}

Отже, foo -hврожайність:

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

Пояснення

cut -d "#" -f 2: Отримати другу частину #розділених рядків. (Подумайте про csv з роздільником "#", порожній перший стовпець).

cut -c 2-: Отримати 2-й до кінця символ результуючого рядка

Також зверніть увагу, що if [ "$1" = "-h" ]обчислюється так, Falseніби немає першого аргументу без помилки, оскільки він стає порожнім рядком.


-1

Поряд з іншими відповідями, згаданими Бармаром та Джоні, я помітив, що іноді мені доводиться залишати порожній рядок до та після мого EOF під час використання <<-EOF.


1
Я не знаходжу для цього підтримки ні в теорії, ні на практиці. Проголосування проти забобонів.
триплі

1
У мене був багаторядковий тут-документ, загорнутий у парені для перенаправлення на catта завдяки форматуванню, безпосередньо перед моїм закриттям маркера тут-документа, мені потрібно було додати Enter перед закриваючим параметром, інакше я отримав би цю невідповідність. Оголошення як цілком дійсне для "деяких" людей, хоча, мабуть, малоймовірний сценарій.
SidOfc

Я ненавиджу робити внесок у забобони, але у мене теж виникала ця проблема, і після закінчення мого EOF я додав порожній рядок. (ubuntu 19.10 працює в docker; це було в сценарії bootstrap.sh). Порожній рядок виправив цю помилку.
NDP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.