here-document đưa ra lỗi 'kết thúc tệp không mong muốn'


81

Tôi cần tập lệnh của mình để gửi email từ thiết bị đầu cuối. Dựa trên những gì tôi đã thấy ở đây và nhiều nơi khác trực tuyến, tôi đã định dạng nó như thế này:

/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

Tuy nhiên, khi tôi chạy cái này, tôi nhận được cảnh báo này:

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

... trong đó dòng x là dòng mã được viết cuối cùng trong chương trình và dòng y là dòng có /var/mailtrong đó. Tôi đã thử thay thế EOFvới những thứ khác ( ENDOFMESSAGE, FINISH, vv) nhưng không có kết quả. Gần như mọi thứ tôi tìm thấy trên mạng đều được thực hiện theo cách này, và tôi thực sự là người mới chơi nên tôi đang gặp khó khăn khi tự mình tìm hiểu. Bất cứ ai có thể cung cấp bất kỳ trợ giúp?


9
EOFdòng thụt? Nó phải ở đầu dòng.
Barmar

Đó là, nhưng chỉ khi toàn bộ câu lệnh đó được lồng vào nhau. Vì vậy, nó phải được tất cả các con đường bên trái?
thnkwthprtls

2
Ngoài ra, đảm bảo không có ký tự dấu (bao gồm cả vận chuyển trở lại!)
glenn Jackman

2
Nếu bạn thụt với chỉ ký tự tab, bạn có thể sử dụng <<-EOF- gnu.org/software/bash/manual/bashref.html#Here-Documents
glenn Jackman

Câu trả lời:


153

EOFthông báo phải ở đầu dòng, bạn không thể thụt lề nó cùng với khối mã mà nó đi cùng.

Nếu bạn viết, <<-EOFbạn có thể thụt lề, nhưng nó phải được thụt lề bằng các Tabký tự, không phải dấu cách. Vì vậy, nó vẫn có thể không kết thúc ngay cả với khối mã.

Ngoài ra hãy chắc chắn rằng bạn không có khoảng trắng sau các EOFdấu hiệu trên đường dây.


2
Trong ví dụ mã ở trên, mã thông báo EOF nằm ở đầu dòng.
Andrew Koster

Tôi không thấy nó trong lịch sử chỉnh sửa, nhưng chắc chắn nó đã được thụt vào ban đầu, vì tôi không phải là người duy nhất chỉ ra vấn đề này.
Barmar

Tôi gặp lỗi này ngay cả khi tôi loại bỏ tất cả các khoảng trắng không cần thiết.
Andrew Koster

Kiểm tra các ký tự CR và sử dụng dos2unixđể sửa chữa nó.
Barmar

17

Dòng bắt đầu hoặc kết thúc here-doc có thể có một số ký tự không thể in được hoặc khoảng trắng (ví dụ: ký tự xuống dòng), có nghĩa là "EOF" thứ hai không khớp với chữ đầu tiên và không kết thúc ở đây-doc như nó nên. Đây là một lỗi rất phổ biến và khó phát hiện chỉ với một trình soạn thảo văn bản. Bạn có thể hiển thị các ký tự không in được, ví dụ cat:

cat -A myfile.sh

Khi bạn nhìn thấy kết quả từ cat -Agiải pháp, bạn sẽ thấy rõ ràng: loại bỏ các ký tự vi phạm.


7

Vui lòng cố gắng xóa các khoảng trắng trước đó EOF: -

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

Sử dụng <tab>thay vì<spaces> cho danh tính VÀ sử dụng << - EOF hoạt động tốt.

Loại "-"bỏ <tabs>, không <spaces>, nhưng ít nhất điều này hoạt động.


2
Đề xuất đầu tiên sẽ không hữu ích (bạn đã kiểm tra xem liệu không gian có gây ra vấn đề không?). Cách thứ hai sẽ chỉ hữu ích nếu dòng EOF được thụt vào bằng TAB, không phải dấu cách.
Barmar

Tôi nghĩ rằng phải dấu hiệu chấm dứt không có không gian hàng đầu
Rahul Tripathi

2

Lưu ý một người cũng có thể gặp lỗi này nếu bạn làm điều này;

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

<< somefilenên đọc < somefiletrong trường hợp này.


0

Đây là một cách linh hoạt để đối phó với nhiều dòng thụt lề mà không cần sử dụng 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

Một số lưu ý về giải pháp này:

  • nếu nội dung được mong đợi có dấu ngoặc kép đơn giản, hãy thoát chúng bằng cách sử dụng \hoặc thay thế các dấu phân cách chuỗi bằng dấu ngoặc kép. Trong trường hợp thứ hai, hãy cẩn thận rằng việc xây dựng như$(command) sẽ được diễn giải. Nếu chuỗi chứa cả dấu ngoặc kép và đơn giản, bạn sẽ phải thoát ít nhất là loại.
  • ví dụ đã cho in một dòng trống ở cuối, có nhiều cách để loại bỏ nó, không được đưa vào đây để giữ cho đề xuất ở mức tối thiểu lộn xộn
  • tính linh hoạt đến từ sự dễ dàng mà bạn có thể kiểm soát bao nhiêu không gian hàng đầu nên ở lại hoặc đi, miễn là bạn biết một số REGEXP sed.

0

Khi tôi muốn có docstrings cho các hàm bash của mình, tôi sử dụng một giải pháp tương tự như đề xuất của user12205 trong một bản sao của câu hỏi này.

Xem cách tôi xác định USAGE cho một giải pháp:

  • tự động định dạng tốt cho tôi trong IDE mà tôi lựa chọn (siêu phàm)
  • là nhiều dòng
  • có thể sử dụng dấu cách hoặc tab làm thụt lề
  • giữ nguyên các thụt đầu dòng trong nhận xét.
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"
}

Vì vậy, foo -hsản lượng:

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

Giải trình

cut -d "#" -f 2: Lấy phần thứ hai của các #dòng được phân tách. (Hãy nghĩ một csv với "#" là dấu phân cách, cột đầu tiên trống).

cut -c 2-: Truy xuất ký tự thứ 2 đến cuối của chuỗi kết quả

Cũng lưu ý rằng if [ "$1" = "-h" ]đánh giá như Falsethể không có đối số đầu tiên, lỗi w / o, vì nó trở thành một chuỗi trống.


-1

Cùng với các câu trả lời khác được đề cập bởi Barmar và Joni, tôi nhận thấy rằng đôi khi tôi phải để lại một dòng trống trước và sau EOF của mình khi sử dụng <<-EOF.


1
Tôi không tìm thấy sự ủng hộ nào cho điều này cả về lý thuyết lẫn thực hành. Phủ nhận là mê tín.
tripleee

1
Tôi có một tài liệu ở đây nhiều dòng được bao bọc trong các dấu phẩy để chuyển hướng đến catvà do định dạng, ngay trước khi đóng dấu ngoặc đơn ở đây, tôi cần thêm dấu enter trước dấu ngoặc đóng nếu không tôi sẽ nhận được sự không khớp này. Ủng hộ là hoàn toàn hợp lệ đối với "một số" người ngoài đó, mặc dù có thể là một kịch bản khó xảy ra.
SidOfc

Tôi không muốn góp phần vào sự mê tín, nhưng tôi cũng gặp phải vấn đề này và đã thêm một dòng trống sau khi kết thúc EOF của mình. (ubuntu 19.10 đang chạy trong docker; đây là một script bootstrap.sh). Dòng trống đã sửa lỗi này.
NDP
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.