Làm thế nào để xuất ra một chuỗi nhiều dòng trong Bash?


250

Làm cách nào tôi có thể xuất một chuỗi nhiều dòng trong Bash mà không sử dụng nhiều lệnh gọi như vậy:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

Tôi đang tìm kiếm một cách di động để làm điều này, chỉ sử dụng các nội trang Bash.


4
Nếu bạn đang xuất một thông báo sử dụng để đáp lại lời mời không chính xác, thông thường bạn sẽ gửi tin nhắn đó đến lỗi tiêu chuẩn thay vì đầu ra tiêu chuẩn, vớiecho >&2 ...
Mark Reed

2
@MarkReed Thông báo sử dụng là đầu ra bằng cách gõ --help(sẽ đi ra tiêu chuẩn).
helpermethod

Đối với những người khác đi cùng, thông tin thêm về "tài liệu ở đây" có sẵn: tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez

Kiểm tra printfgiải pháp dựa trên cơ sở từ Gordon Davidson. Mặc dù trong bóng tối của các phương pháp tiếp cận echohoặc catdựa trên, nó dường như ít hơn nhiều so với bùn. Phải thừa nhận rằng cú pháp `printf 'đại diện cho một chút của đường cong học tập, nhưng tôi muốn nghe những nhược điểm khác (? Khả năng tương thích, hiệu suất? ...)
mjv

Câu trả lời:


296

Ở đây các tài liệu thường được sử dụng cho mục đích này.

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

Chúng được hỗ trợ trong tất cả các shell có nguồn gốc từ Bourne, bao gồm tất cả các phiên bản của Bash.


4
Yup - nhưng catkhông phải là tích hợp.
Mark Reed

8
@MarkReed: Điều đó đúng, nhưng nó luôn có sẵn (ngoại trừ có thể trong những trường hợp bất thường).
Tạm dừng cho đến khi có thông báo mới.

6
+1 Thx. Cuối cùng tôi đã sử dụng read -d '' help <<- EOF ...để đọc chuỗi multiline thành một biến và sau đó lặp lại kết quả.
helpermethod

3
Tôi có thể lưu HEREDOC vào một biến không?
chovy

177

hoặc bạn có thể làm điều này:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "

1
@Oliver Weiler: Nó thậm chí sẽ hoạt động trong các vỏ Bourne như Dash và Heirloom Bourne Shell .
Tạm dừng cho đến khi có thông báo mới.

6
Không tuyệt vời nếu bạn cần điều này trong một hàm bởi vì bạn sẽ cần 1) vượt quá chuỗi bên trái của tệp của bạn hoặc 2) giữ cho nó được thụt lề để xếp hàng với phần còn lại của mã của bạn nhưng sau đó nó sẽ in cũng như thụt lề
sg

43

Lấy cảm hứng từ những câu trả lời sâu sắc trên trang này, tôi đã tạo ra một cách tiếp cận hỗn hợp, mà tôi cho là cách đơn giản nhất và linh hoạt hơn. Bạn nghĩ sao?

Đầu tiên, tôi xác định việc sử dụng trong một biến, cho phép tôi sử dụng lại nó trong các bối cảnh khác nhau. Định dạng rất đơn giản, gần như WYSIWYG, không cần thêm bất kỳ ký tự điều khiển nào. Cái này có vẻ hợp lý với tôi (tôi đã chạy nó trên MacOS và Ubuntu)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

Sau đó, tôi chỉ có thể sử dụng nó như là

echo "$__usage"

hoặc thậm chí tốt hơn, khi phân tích cú pháp các tham số, tôi chỉ có thể lặp lại nó ở đó trong một lớp lót:

levelN=${2:?"--level: n is required!""${__usage}"}

4
điều này làm việc cho tôi trong một kịch bản mà câu trả lời ở trên không (không sửa đổi).
David Welch

3
Điều này sạch sẽ hơn nhiều so với việc liên quan đến một loạt các ký tự như \ t và \ n khó tìm thấy trong văn bản và mở rộng để làm cho đầu ra khác nhiều so với chuỗi trong tập lệnh
sg

1
Vì một số lý do, nó in mọi thứ trên cùng một dòng cho tôi: /
Nicolas de Fontenay

2
@Nicolas: Sử dụng dấu ngoặc kép trong echo "$__usage"là cần thiết đối với tôi. echo $__usageđã không làm việc.
Mario

24

Sử dụng -etùy chọn, sau đó bạn có thể in ký tự dòng mới với\n trong chuỗi.

Mẫu vật (nhưng không chắc có tốt hay không)

Điều thú vị là -etùy chọn này không được ghi lại trong trang man của MacOS trong khi vẫn có thể sử dụng được. Nó được ghi lại trong trang con người của Linux .


6
Những trang người đàn ông là dành cho các hệ thống cung cấp echolệnh, /bin/echomà trên Mac OS không có -elựa chọn. khi bạn đang sử dụng bash trên các hệ thống đó, echolệnh tích hợp của nó sẽ tiếp tục. Bạn có thể thấy điều này bằng cách gõ rõ ràng /bin/echo whatevervà quan sát sự khác biệt trong hành vi. Để xem tài liệu cho tích hợp, gõ help echo.
Mark Reed

1
/bin/echothường khác với HĐH này và HĐH khác và khác với nội dung của Bash echo.
Tạm dừng cho đến khi có thông báo mới.

@MarkReed: Tôi sẽ thử sau, nhưng cảm ơn vì thông tin. +1. Tôi sẽ chỉ để lại câu trả lời của mình ở đây, vì có khá nhiều cuộc thảo luận tốt đang diễn ra.
nhahtdh

7
echo -ekhông khả dụng - ví dụ, một số triển khai của echo sẽ in "-e" như một phần của đầu ra. Nếu bạn muốn tính di động, sử dụng printf thay thế. Ví dụ: / bin / echo trên OS X 10.7.4 thực hiện việc này. IIRC tiếng vang dựng sẵn bash cũng kỳ lạ theo 10.5.0, nhưng tôi không nhớ chi tiết nữa.
Gordon Davisson

2
echo -eđã cắn tôi trước khi ... Chắc chắn sử dụng printfhoặc catvới một di sản. Các <<-biến thể của tài liệu ở đây đặc biệt tốt vì bạn có thể loại bỏ thụt đầu dòng ở đầu ra, nhưng thụt vào để đọc trong kịch bản
zbeekman

22

Vì tôi đã đề xuất printftrong một nhận xét, có lẽ tôi nên đưa ra một số ví dụ về cách sử dụng nó (mặc dù để in một thông điệp sử dụng, tôi có nhiều khả năng sử dụng câu trả lời của Dennis hoặc Chris). printflà một chút phức tạp để sử dụng hơn echo. Đối số đầu tiên của nó là một chuỗi định dạng, trong đó thoát (như \n) luôn được diễn giải; nó cũng có thể chứa các chỉ thị định dạng bắt đầu bằng %, điều khiển ở đâu và làm thế nào bất kỳ đối số bổ sung nào được bao gồm trong đó. Dưới đây là hai cách tiếp cận khác nhau để sử dụng nó cho thông điệp sử dụng:

Đầu tiên, bạn có thể bao gồm toàn bộ tin nhắn trong chuỗi định dạng:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

Lưu ý rằng không giống như echo, bạn phải bao gồm dòng mới cuối cùng một cách rõ ràng. Ngoài ra, nếu thông báo có chứa bất kỳ %ký tự nào , chúng sẽ phải được viết dưới dạng %%. Nếu bạn muốn bao gồm các địa chỉ trang chủ và lỗi, chúng có thể được thêm vào một cách khá tự nhiên:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

Thứ hai, bạn chỉ có thể sử dụng chuỗi định dạng để làm cho nó in từng đối số bổ sung trên một dòng riêng biệt:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

Với tùy chọn này, việc thêm địa chỉ bugreport và trang chủ là khá rõ ràng:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"

9

Ngoài ra với mã nguồn thụt lề, bạn có thể sử dụng <<-(với dấu gạch ngang) để bỏ qua các tab hàng đầu (nhưng không phải là khoảng trắng hàng đầu). Ví dụ này:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

Đầu ra văn bản thụt lề mà không có khoảng trắng hàng đầu:

line1
line2

Điều đó đã không làm việc cho tôi. Bạn đang sử dụng vỏ gì?
bốn43

Không hoạt động trong bash 4.4.19 trong Ubuntu. Nó không xóa khoảng cách trước
dòng1

1
@ Four43, Bạn đã đúng. Không hoạt động để loại bỏ không gian hàng đầu. Tuy nhiên, không loại bỏ các tab hàng đầu. Vì vậy, tôi đã sửa câu trả lời của mình từ tab và khoảng trắng, sang tab và không phải khoảng trắng. Xin lỗi vì những lỗi lầm. Tôi đã kiểm tra hướng dẫn và nó rõ ràng chỉ nói các tab được gỡ bỏ. Cảm ơn vì đã mang đến sự chú ý của tôi.
Chế độ xem hình elip

0

Nếu bạn sử dụng giải pháp từ @jorge và thấy rằng mọi thứ đều nằm trên cùng một dòng, hãy đảm bảo bạn kèm theo biến trong dấu ngoặc kép:

echo $__usage

sẽ in mọi thứ trên một dòng trong khi

echo "$__usage"

sẽ giữ lại các dòng mới.


Đây thực sự là một giải pháp hiệu quả với tôi. Printf thực hiện rất nhiều thứ và với xml multiline của tôi, nó có thể đòi hỏi rất nhiều thoát vì nó hoàn toàn làm hỏng nội dung. Tôi gán foo =cat <<EOF .... EOF && echo "$ foo"
Jilles van Gurp
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.