Chuỗi nhiều dòng có thêm không gian (thụt đầu dòng)


410

Tôi muốn viết một số văn bản được xác định trước vào một tệp với nội dung sau:

text="this is line one\n
this is line two\n
this is line three"

echo -e $text > filename

Tôi đang mong đợi một cái gì đó như thế này:

this is line one
this is line two
this is line three

Nhưng có được điều này:

this is line one
 this is line two
 this is line three

Tôi khẳng định rằng không có không gian sau mỗi lần \n, nhưng làm thế nào để có thêm không gian?


2
Tôi không chắc nhưng .. làm thế nào nếu bạn chỉ gõ text="this is line one\nthis is line two\nthis is line three"vào cùng một dòng ..? (không có bất kỳ sự xâm nhập nào)
Yohanes Khosiawan

4
Xóa dòng \ntrên mỗi dòng, bạn đã nhấn dòng mới để chuyển sang dòng mới
Mark Setchell

Bạn đã đưa ra \n. Vì vậy, tại sao bạn đặt dòng tiếp theo trong dòng mới? Đơn giảntext="this is line one\nthis is line two\nthis is line three"
Jayesh Bhoi

1
Loại bỏ \nở cuối mỗi dòng làm cho đầu ra tất cả chạy cùng nhau trên một dòng.
Jonathan Hartley

18
Aha: Đặt dấu ngoặc kép xung quanh "$text"trong dòng echo là rất quan trọng. Không có chúng, không có dòng mới nào (cả nghĩa đen và '\ n') hoạt động. Với họ, tất cả họ làm.
Jonathan Hartley

Câu trả lời:


663

Heredoc âm thanh thuận tiện hơn cho mục đích này. Nó được sử dụng để gửi nhiều lệnh đến một chương trình thông dịch lệnh như ex hoặc cat

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

Chuỗi sau <<chỉ ra nơi dừng lại.

Để gửi những dòng này đến một tệp, sử dụng:

cat > $FILE <<- EOM
Line 1.
Line 2.
EOM

Bạn cũng có thể lưu trữ các dòng này vào một biến:

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

Điều này lưu trữ các dòng đến biến có tên VAR.

Khi in, hãy nhớ các trích dẫn xung quanh biến nếu không bạn sẽ không thấy các ký tự dòng mới.

echo "$VAR"

Thậm chí tốt hơn, bạn có thể sử dụng thụt lề để làm cho nó nổi bật hơn trong mã của bạn. Lần này chỉ cần thêm một -sau <<để ngăn các tab xuất hiện.

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

Nhưng sau đó, bạn phải sử dụng các tab, không phải khoảng trắng, để thụt lề trong mã của bạn.


38
tại sao bạn có << - thay vì << trên dòng đầu tiên của khối mã thứ 2 và thứ 5? không - làm gì đặc biệt?
lohfu

35
@ sup3rman '-' Bỏ qua các tab hàng đầu. Xem stackoverflow.com/questions/2500436/ từ
kervin

8
Làm thế nào tôi có thể thực hiện đọc thoát với trạng thái 0? Có vẻ như nó không thể tìm thấy cuối dòng (vì nó là '' ') và thoát với 1 mà không giúp ích gì khi bạn ở trong kịch bản.
Misha Slyusarev

7
@MishaSlyusarev sử dụng -d '\ 0' và thêm \ 0 ở cuối dòng cuối cùng của bạn
Lars Schneider

11
Sử dụng -dtùy chọn trong read -r -d '' VARIABLE <<- EOMkhông làm việc cho tôi.
dron22

186

Nếu bạn đang cố gắng đưa chuỗi thành một biến, một cách dễ dàng khác là như thế này:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

Nếu bạn thụt chuỗi của mình bằng các tab (nghĩa là '\ t'), thì thụt lề sẽ bị loại bỏ. Nếu bạn thụt lề với khoảng trắng, vết lõm sẽ được để lại.

Chú ý: Đây ý nghĩa rằng đóng ngoặc cuối cùng là trên đường dây khác. Văn ENDbản phải tự xuất hiện trên một dòng.


1
Điều đó có đáng kể không? Hoạt động trên mac của tôi với )trên cùng một dòng. Tôi nghĩ đó là bởi vì những gì diễn ra giữa $()sẽ thực thi trong vũ trụ của chính nó và dù sao thì lệnh thực tế sẽ không thấy ')'. Tôi tự hỏi nếu nó làm việc cho người khác quá.
deej

Có thể các vỏ khác nhau sẽ diễn giải mọi thứ khác nhau. Trong tài liệu bash dường như không nói bất cứ điều gì theo cách này hay cách khác, nhưng tất cả các ví dụ đều có nó trên dòng riêng của nó.
Thợ mỏ Andrew

Điều thú vị là, tôi thấy bạn trả lời khi cố gắng đặt giá trị cho biến USAGE. Vì vậy, câu trả lời của bạn phù hợp chính xác. :)
Bunyk

1
@deej Từ thông số kỹ thuật POSIX : Tài liệu ở đây tiếp tục cho đến khi có một dòng chỉ chứa dấu phân cách và <dòng mới>
Từ

1
@Fornost Nó không mâu thuẫn với những gì tôi đã nói
deej

84

echothêm khoảng trắng giữa các đối số được truyền cho nó. $textcó thể mở rộng biến và chia tách từ, vì vậy echolệnh của bạn tương đương với:

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

Bạn có thể thấy rằng một khoảng trắng sẽ được thêm vào trước "này". Bạn có thể xóa các ký tự dòng mới và trích dẫn $textđể giữ nguyên các dòng mới:

text="this is line one
this is line two
this is line three"

echo "$text" > filename

Hoặc bạn có thể sử dụng printf, mạnh mẽ và di động hơn echo:

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

Trong bash, hỗ trợ mở rộng niềng răng, bạn thậm chí có thể làm:

printf "%s\n" "this is line "{one,two,three} > filename

1
Cảm ơn đã giải thích lý do tại sao mod nhìn thấy không gian thêm khi sử dụng lệnh echo echo. Câu trả lời này cũng hoạt động tốt khi sử dụng trong bash script (trái ngược với phiên shell tương tác). Cảm thấy như đây là câu trả lời thực sự và nên là một câu trả lời được chấp nhận.
onelaview

1
Điều này nên được chấp nhận câu trả lời. Tất cả các câu trả lời khác cung cấp vô số cách thú vị khác để giải quyết nỗi đau của OP, nhưng về mặt kỹ thuật, câu hỏi là "làm thế nào để có thêm không gian" và không ai giải quyết điều này :-) !!! Cảm ơn bạn, Josh đã làm -1 bí ẩn!
Dmitry Shevkoplyas

45

trong một tập lệnh bash các tác phẩm sau:

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename

cách khác:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

tên tệp mèo cho:

this is line one
this is line two
this is line three

Có vẻ như thủ thuật thay thế hoạt động trong khi Shell Sc Script nhưng dường như nó không hoạt động đối với bash.
Macindows

3
@Macindows Tôi dường như đã quên -etùy chọn này echo. Vui lòng thử lại.
Chris Maes

41

Tôi đã tìm thấy nhiều giải pháp hơn vì tôi muốn mọi dòng được thụt lề đúng cách:

  1. Bạn có thể sử dụng echo:

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename

    Nó không hoạt động nếu bạn đặt "\n"ngay trước khi \kết thúc một dòng.

  2. Ngoài ra, bạn có thể sử dụng printfđể có tính di động tốt hơn (tôi đã gặp rất nhiều vấn đề với echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
  3. Một giải pháp khác có thể là:

    text=''
    text="${text}this is line one\n"
    text="${text}this is line two\n"
    text="${text}this is line three\n"
    printf "%b" "$text" > filename

    hoặc là

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
  4. Một giải pháp khác đạt được bằng cách trộn printfsed.

    if something
    then
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    fi

    Không dễ để tái cấu trúc mã được định dạng như thế này khi bạn mã hóa mức độ thụt vào mã.

  5. Có thể sử dụng chức năng trợ giúp và một số thủ thuật thay thế:

    unset text
    _() { text="${text}${text+
    }${*}"; }
    # That's an empty line which demonstrates the reasoning behind 
    # the usage of "+" instead of ":+" in the variable substitution 
    # above.
    _ ""
    _ "this is line one"
    _ "this is line two"
    _ "this is line three"
    unset -f _
    printf '%s' "$text"

3b là giải pháp ưa thích của tôi khi muốn duy trì thụt mã độc lập và thụt chuỗi độc lập, ít nhất là khi tôi không thể sử dụng 2 trong phép gán biến và dễ đọc hơn 3a. Khi tôi không quan tâm, tôi chỉ giữ chuỗi trích dẫn mở trên một vài dòng.
Pysis

Câu trả lời rất hay, đặc biệt là 3b
Sumit Trehan

"Nó không hoạt động nếu bạn đặt" \ n "ngay trước \ ở cuối dòng." - là một mẹo tuyệt vời khi sử dụng echo.
Noam Manos

6

Sau đây là cách ưa thích của tôi để gán một chuỗi nhiều dòng cho một biến (tôi nghĩ rằng nó trông đẹp).

read -r -d '' my_variable << \
_______________________________________________________________________________

String1
String2
String3
...
StringN
_______________________________________________________________________________

Số lượng dấu gạch dưới là như nhau (ở đây là 80) trong cả hai trường hợp.


0

Chỉ cần đề cập đến một cách ghép một dòng đơn giản vì đôi khi nó có thể hữu ích.

# for bash

v=" guga "$'\n'"   puga "

# Just for an example.
v2="bar "$'\n'"   foo "$'\n'"$v"

# Let's simplify the previous version of $v2.
n=$'\n'
v3="bar ${n}   foo ${n}$v"

echo "$v3" 

Bạn sẽ nhận được một cái gì đó như thế này

quán ba 
   foo 
 guga 
   puga 

Tất cả các khoảng trắng hàng đầu và kết thúc sẽ được bảo tồn ngay cho

echo "$v3" > filename

0

Có rất nhiều cách để làm điều đó. Đối với tôi, đường ống thụt vào trong sed hoạt động độc đáo.

printf_strip_indent() {
   printf "%s" "$1" | sed "s/^\s*//g" 
}

printf_strip_indent "this is line one
this is line two
this is line three" > "file.txt"

Câu trả lời này dựa trên câu trả lời của Mateusz Piotrowski nhưng đã tinh chỉnh một chút.


-1

nó sẽ hoạt động nếu bạn đặt nó như dưới đây:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
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.