Dòng tiếp tục Bash


158

Làm thế nào để bạn sử dụng các dòng tiếp tục bash?

Tôi nhận ra rằng bạn có thể làm điều này:

echo "continuation \
lines"
>continuation lines

Tuy nhiên, nếu bạn có mã thụt lề, nó không hoạt động tốt như vậy:

    echo "continuation \
    lines"
>continuation     lines

5
Hướng dẫn về phong cách Bash Shell của Google khuyến nghị các tài liệu "ở đây" cho "Nếu bạn phải viết các chuỗi dài hơn 80 ký tự". Xem câu trả lời của @ tripleee .
Trevor Boyd Smith

google.github.io/styleguide/ trộm - đây là liên kết trực tiếp trong tài liệu mới
jcollum

Câu trả lời:


161

Đây là những gì bạn có thể muốn

$       echo "continuation"\
>       "lines"
continuation lines

Nếu điều này tạo ra hai đối số để lặp lại và bạn chỉ muốn một đối số, thì hãy xem xét nối chuỗi. Trong bash, đặt hai chuỗi cạnh nhau:

$ echo "continuation""lines"
continuationlines

Vì vậy, một dòng tiếp tục không có thụt lề là một cách để phá vỡ một chuỗi:

$ echo "continuation"\
> "lines"
continuationlines

Nhưng khi thụt lề được sử dụng:

$       echo "continuation"\
>       "lines"
continuation lines

Bạn nhận được hai đối số bởi vì đây không còn là một kết nối.

Nếu bạn muốn một chuỗi đơn đi qua các dòng, trong khi thụt lề nhưng không nhận được tất cả các khoảng trắng đó, một cách tiếp cận bạn có thể thử là bỏ dòng tiếp tục và sử dụng các biến:

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

Điều này sẽ cho phép bạn có mã thụt lề sạch với chi phí của các biến bổ sung. Nếu bạn thực hiện các biến cục bộ thì nó không quá tệ.


1
Cảm ơn sự giúp đỡ của bạn, nhưng trong khi điều này loại bỏ khoảng trắng, giờ đây chúng là các tham số riêng biệt (Bash đang diễn giải các khoảng trắng trên dòng thứ hai dưới dạng dấu tách tham số) và hiện chỉ được in chính xác do lệnh echo.

1
Ồ, bạn muốn một chuỗi (bash) để kéo dài dòng! Tôi thấy bây giờ
Ray Toal

4
Giải pháp với một biến:s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
Johnny Thunderman

30

Ở đây các tài liệu với bộ <<-HEREkết thúc hoạt động tốt cho các chuỗi văn bản nhiều dòng thụt vào. Nó sẽ xóa bất kỳ tab hàng đầu khỏi tài liệu ở đây. (Tuy nhiên, các đầu cuối dòng sẽ vẫn còn.)

cat <<-____HERE
    continuation
    lines
____HERE

Xem thêm http://ss64.com/bash/syntax-here.html

Nếu bạn cần giữ một số, nhưng không phải tất cả, khoảng trắng hàng đầu, bạn có thể sử dụng cái gì đó như

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

hoặc có thể sử dụng trđể thoát khỏi dòng mới:

tr -d '\012' <<-____
    continuation
     lines
____

(Dòng thứ hai có một tab và một khoảng trắng ở phía trước; tab sẽ bị xóa bởi toán tử dấu gạch ngang trước dấu kết thúc di truyền, trong khi khoảng trắng sẽ được giữ nguyên.)

Để gói các chuỗi dài phức tạp trên nhiều dòng, tôi thích printf:

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

Nó cũng hoạt động tốt trong các ngữ cảnh nơi bạn muốn nhúng các đoạn mã shell không cần thiết vào một ngôn ngữ khác trong đó cú pháp của ngôn ngữ máy chủ sẽ không cho phép bạn sử dụng tài liệu ở đây, chẳng hạn như trong Makefilehoặc Dockerfile.

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript

Không làm việc cho tôi. Ubuntu 16.04. Tôi nhận được hai dòng thay vì dự kiến ​​nối một dòng.
Penghe Geng

@PengheGeng Thật vậy, điều này giải quyết vấn đề thoát khỏi vết lõm, không phải là một trong những đường nối với nhau. Bạn vẫn có thể gạch chéo dòng mới ở cuối dòng để nối hai dòng với nhau.
tripleee

(Nhưng hãy xem printfví dụ đầu tiên ngay bây giờ.)
tripleee

12

Bạn có thể sử dụng mảng bash

$ str_array=("continuation"
             "lines")

sau đó

$ echo "${str_array[*]}"
continuation lines

có thêm một không gian, bởi vì (sau hướng dẫn bash):

Nếu từ được trích dẫn kép, ${name[*]}mở rộng thành một từ duy nhất với giá trị của từng thành viên mảng được phân tách bằng ký tự đầu tiên của biến IFS

Vì vậy, thiết lập IFS=''để thoát khỏi không gian thêm

$ IFS=''
$ echo "${str_array[*]}"
continuationlines

4

Trong một số tình huống nhất định sử dụng khả năng nối của Bash có thể phù hợp.

Thí dụ:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

Từ phần PARAMETERS của trang Bash Man:

tên = [giá trị] ...

... Trong ngữ cảnh mà một câu lệnh gán đang gán một giá trị cho biến shell hoặc chỉ mục mảng, toán tử + = có thể được sử dụng để nối thêm hoặc thêm vào giá trị trước đó của biến. Khi + = được áp dụng cho một biến mà thuộc tính số nguyên đã được đặt, giá trị được đánh giá là biểu thức số học và được thêm vào giá trị hiện tại của biến, cũng được ước tính. Khi + = được áp dụng cho một biến mảng bằng cách sử dụng phép gán hỗn hợp (xem Mảng bên dưới), giá trị của biến không được đặt (như khi sử dụng =) và các giá trị mới được thêm vào mảng bắt đầu bằng một chỉ số lớn hơn chỉ số tối đa của mảng (đối với các mảng được lập chỉ mục) hoặc được thêm dưới dạng các cặp khóa-giá trị bổ sung trong một mảng kết hợp. Khi được áp dụng cho biến có giá trị chuỗi, giá trị được mở rộng và gắn vào giá trị của biến.


Có lẽ là lời khuyên tốt nhất trên trang này. Sử dụng HEREDOC và chuyển thành một bản dịch cho <CR> là siêu không trực quan và thất bại khi chuỗi thực sự cần phải có các dấu tách dòng được đặt một cách riêng biệt.
vào

2

Tôi đã gặp một tình huống trong đó tôi phải gửi một tin nhắn dài như một phần của đối số lệnh và phải tuân thủ giới hạn độ dài dòng. Các lệnh trông giống như thế này:

somecommand --message="I am a long message" args

Cách tôi giải quyết điều này là chuyển thông điệp ra dưới dạng tài liệu ở đây (như @tripleee đề xuất). Nhưng một tài liệu ở đây trở thành một stdin, vì vậy nó cần được đọc lại, tôi đã thực hiện theo cách tiếp cận dưới đây:

message=$(
    tr "\n" " " <<- END
        This is a
        long message
END
)
somecommand --message="$message" args

Điều này có lợi thế $messagecó thể được sử dụng chính xác như hằng chuỗi mà không có khoảng trắng hoặc ngắt dòng bổ sung.

Lưu ý rằng các dòng thông báo thực tế ở trên có tiền tố tabmỗi ký tự, được loại bỏ bởi chính tài liệu này (vì sử dụng <<-). Vẫn có các ngắt dòng ở cuối, sau đó được thay thế bằng ddkhoảng trắng.

Cũng lưu ý rằng nếu bạn không xóa dòng mới, chúng sẽ xuất hiện như khi "$message"được mở rộng. Trong một số trường hợp, bạn có thể giải quyết bằng cách xóa dấu ngoặc kép xung quanh $message, nhưng thông báo sẽ không còn là một đối số duy nhất.


2

Tiếp tục dòng cũng có thể đạt được thông qua việc sử dụng cú pháp thông minh.

Trong trường hợp echo:

# echo '-n' flag prevents trailing <CR> 
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.

Trong trường hợp của vars:

outp="This is my one-line statement" ; 
outp+=" that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

Một cách tiếp cận khác trong trường hợp của vars:

outp="This is my one-line statement" ; 
outp="${outp} that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

Voila!


1

Bạn có thể chỉ cần tách nó bằng các dòng mới (không sử dụng dấu gạch chéo ngược) theo yêu cầu trong phần thụt lề như sau và chỉ dải các dòng mới.

Thí dụ:

echo "continuation
of 
lines" | tr '\n' ' '

Hoặc nếu đó là một định nghĩa mới, các dòng mới sẽ tự động được chuyển đổi thành dấu cách. Vì vậy, dải không gian thêm chỉ khi áp dụng.

x="continuation
of multiple
lines"
y="red|blue|
green|yellow"

echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case

1

Đây không phải là chính xác những gì người dùng đã hỏi, nhưng một cách khác để tạo một chuỗi dài kéo dài nhiều dòng là bằng cách tăng dần nó lên, như vậy:

$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World

Rõ ràng trong trường hợp này sẽ đơn giản hơn để xây dựng nó một lần, nhưng phong cách này có thể rất nhẹ và dễ hiểu khi xử lý các chuỗi dài hơn.


0

Tuy nhiên, nếu bạn có mã thụt lề, nó không hoạt động tốt như vậy:

    echo "continuation \
    lines"
>continuation     lines

Hãy thử với dấu ngoặc đơn và nối các chuỗi:

    echo 'continuation' \
    'lines'
>continuation lines

Lưu ý: phần nối bao gồm một khoảng trắng.


2
Nó hoạt động với các đối số echo và chuỗi, nhưng nó không hoạt động với những thứ khác, như gán biến. Mặc dù câu hỏi không phải là về các biến, sử dụng echo chỉ là một ví dụ. Thay vì echo nếu bạn có x=, bạn sẽ gặp lỗi : lines: command not found.
LS

0

Tùy thuộc vào loại rủi ro nào bạn sẽ chấp nhận và mức độ bạn biết và tin tưởng vào dữ liệu, bạn có thể sử dụng phép nội suy biến đơn giản.

$: x="
    this
    is
       variably indented
    stuff
   "
$: echo "$x" # preserves the newlines and spacing

    this
    is
       variably indented
    stuff

$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff

-2

Điều này có thể không thực sự trả lời câu hỏi của bạn nhưng dù sao bạn cũng có thể thấy nó hữu ích.

Lệnh đầu tiên tạo tập lệnh được hiển thị bởi lệnh thứ hai.

Lệnh thứ ba làm cho kịch bản đó có thể thực thi được.

Lệnh thứ tư cung cấp một ví dụ sử dụng.

john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent 
#!/usr/bin/env python
import textwrap, sys

def bash_dedent(text):
    """Dedent all but the first line in the passed `text`."""
    try:
        first, rest = text.split("\n", 1)
        return "\n".join([first, textwrap.dedent(rest)])
    except ValueError:
        return text  # single-line string

print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
>     second line
>     third line")"
first line
second line
third line

Lưu ý rằng nếu bạn thực sự muốn sử dụng tập lệnh này, sẽ có ý nghĩa hơn khi di chuyển tập lệnh thực thi vào ~/binđể nó sẽ nằm trong đường dẫn của bạn.

Kiểm tra tham chiếu python để biết chi tiết về cách làm textwrap.dedentviệc.

Nếu việc sử dụng $'...'hoặc "$(...)"gây nhầm lẫn cho bạn, hãy hỏi một câu hỏi khác (mỗi câu hỏi trên một cấu trúc) nếu chưa có một câu hỏi nào. Có thể rất tốt khi cung cấp một liên kết đến câu hỏi bạn tìm / hỏi để những người khác sẽ có một tài liệu tham khảo được liên kết.


6
Có ý định tốt - và thậm chí có thể hữu ích - mặc dù điều này có thể là, OP đã yêu cầu lời khuyên về cú pháp bash cơ bản và bạn đã đưa cho anh ta một định nghĩa hàm python sử dụng mô hình OO, kiểm soát luồng đặc biệt và nhập khẩu. Hơn nữa, bạn đã gọi một tệp thực thi như là một phần của phép nội suy chuỗi - thứ mà một người hỏi loại câu hỏi này chắc chắn sẽ không thấy trong bash.
Bắn Parthian
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.