Здесь-документ дает ошибку "неожиданный конец файла"

Мне нужен мой скрипт для отправки электронного письма с терминала. Основываясь на том, что я видел здесь и во многих других местах в Интернете, я отформатировал его так:

/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, поэтому мне сложно разобраться в этом самостоятельно. Может ли кто-нибудь предложить какую-либо помощь?

10 ответов

Решение

EOF токен должен быть в начале строки, вы не можете сделать отступ вместе с блоком кода, с которым он идет.

Если ты пишешь <<-EOF Вы можете сделать отступ, но он должен содержать отступы, а не пробелы. Так что это все еще может не закончиться даже с блоком кода.

Также убедитесь, что у вас нет пробелов после EOF жетон на линии.

Строка, которая начинает или заканчивает Here-Doc, вероятно, содержит некоторые непечатаемые или пробельные символы (например, возврат каретки), что означает, что второй "EOF" не совпадает с первым, и не заканчивается должно. Это очень распространенная ошибка, которую трудно обнаружить с помощью текстового редактора. Вы можете сделать непечатные символы видимыми, например, с помощью cat:

cat -A myfile.sh

Как только вы увидите выход из cat -A решение будет очевидным: удалите оскорбительные символы.

Пожалуйста, попробуйте удалить предыдущие пробелы, прежде чем EOF:-

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

С помощью <tab> вместо <spaces> для идентификации и использования << - EOF работает нормально.

"-" удаляет <tabs>не <spaces>, но по крайней мере это работает.

Для тех, кто спотыкается здесь, кто гуглил «предупреждение bash: здесь-документ, разделенный концом файла» , возможно, вы получаете

предупреждение: здесь-документ в строке 74 разделен концом файла

... введите предупреждение, потому что вы случайно использовали здесь символ документа ( <<), когда вы хотели использовать строковый символ здесь ( <<<). Это был мой случай.

Обратите внимание, что при этом также может появиться эта ошибка;

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

Потому как << somefile должен прочесть < somefile в этом случае.

Может быть, это старо, но у меня был пробел после окончания EOF << EOFblahblahEOF <- вот в чем проблема. Прошло много лет, наконец-то посмотрел здесь

Когда я хочу иметь строки документации для моих функций bash, я использую решение, подобное предложению ace в дубликате этого вопроса.

Посмотрите, как я определяю ИСПОЛЬЗОВАНИЕ для решения, которое:

  • автоформатирование хорошо для меня в моей выбранной среде 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-: Получить второй до конца символ результирующей строки

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

убедитесь, что вы помещаете конечный EOF, вы помещаете его в начало новой строки

Наряду с другими ответами, упомянутыми Бармаром и Джони, я заметил, что мне иногда приходится оставлять пустую строку до и после моего EOF при использовании <<-EOF,

Вот гибкий способ справиться с несколькими строками с отступом без использования 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.
Другие вопросы по тегам