Tali multi-garis dengan ruang ekstra (lekukan yang diawetkan)

410

Saya ingin menulis beberapa teks yang telah ditentukan ke file dengan yang berikut ini:

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

echo -e $text > filename

Saya mengharapkan sesuatu seperti ini:

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

Tapi dapatkan ini:

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

Saya yakin tidak ada ruang setelah masing-masing \n, tetapi bagaimana ruang ekstra keluar?

cizixs
sumber
2
Saya tidak yakin tapi .. bagaimana jika Anda hanya mengetik text="this is line one\nthis is line two\nthis is line three"satu baris yang sama ..? (tanpa masukkan)
Yohanes Khosiawan 许先汉
4
Hapus \ndi setiap baris, Anda telah menekan baris baru untuk pindah ke baris baru
Mark Setchell
Anda sudah memberikan \n.Jadi mengapa Anda menempatkan baris berikutnya di baris baru? Sederhananyatext="this is line one\nthis is line two\nthis is line three"
Jayesh Bhoi
1
Menghapus \npada akhir setiap baris menyebabkan output semua berjalan bersama pada satu baris.
Jonathan Hartley
18
Aha: Menempatkan tanda kutip ganda "$text"di dalam garis gema sangat penting. Tanpa mereka, tidak ada baris baru (baik literal maupun '\ n') yang berfungsi. Dengan mereka, mereka semua melakukannya.
Jonathan Hartley

Jawaban:

663

Heredoc terdengar lebih nyaman untuk tujuan ini. Ini digunakan untuk mengirim banyak perintah ke program juru bahasa perintah seperti ex atau cat

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

String setelah <<menunjukkan di mana harus berhenti.

Untuk mengirim baris ini ke file, gunakan:

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

Anda juga bisa menyimpan garis-garis ini ke variabel:

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

Ini menyimpan garis ke variabel bernama VAR.

Saat mencetak, ingat tanda kutip di sekitar variabel jika tidak, Anda tidak akan melihat karakter baris baru.

echo "$VAR"

Bahkan lebih baik, Anda dapat menggunakan lekukan untuk membuatnya lebih menonjol dalam kode Anda. Kali ini tambahkan saja -setelah <<untuk menghentikan tab agar tidak muncul.

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

Tetapi kemudian Anda harus menggunakan tab, bukan spasi, untuk lekukan dalam kode Anda.

anak baru
sumber
38
mengapa Anda memiliki << - alih-alih << pada baris pertama blok kode 2 dan 5? tidak - melakukan sesuatu yang istimewa?
lohfu
35
@ sup3rman '-' Mengabaikan tab terkemuka. Lihat stackoverflow.com/questions/2500436/…
kervin
8
bagaimana saya bisa membuat read exit dengan status 0? Sepertinya tidak dapat menemukan ujung baris (karena ini -d '') dan keluar dengan 1 yang tidak membantu ketika Anda berada dalam skrip.
Misha Slyusarev
7
@MishaSlyusarev gunakan -d '\ 0' dan tambahkan \ 0 di akhir baris terakhir Anda
Lars Schneider
11
Menggunakan -dopsi dalam read -r -d '' VARIABLE <<- EOMtidak berhasil untuk saya.
dron22
186

Jika Anda mencoba memasukkan string ke dalam variabel, cara mudah lainnya adalah seperti ini:

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

Jika Anda membuat indentasi string Anda dengan tab (yaitu, '\ t'), indentasi akan dilucuti. Jika Anda indentasi dengan spasi, indentasi akan dibiarkan masuk.

CATATAN: Ini adalah penting bahwa penutupan kurung terakhir adalah pada baris lain. The ENDteks harus muncul pada baris dengan sendirinya.

Andrew Miner
sumber
1
Apakah itu penting? Bekerja di mac saya dengan )di baris yang sama. Saya pikir itu karena apa yang terjadi di antara $(dan )akan dieksekusi di alam semesta sendiri, dan perintah yang sebenarnya tidak akan melihat ')'. Saya ingin tahu apakah itu bekerja untuk orang lain juga.
deej
Ada kemungkinan bahwa cangkang yang berbeda akan menafsirkan hal-hal secara berbeda. Dalam dokumentasi bash , tampaknya tidak mengatakan apa pun dengan cara apa pun, tetapi semua contoh memilikinya di jalurnya sendiri.
Andrew Miner
Yang menyenangkan adalah, saya menemukan Anda menjawab ketika mencoba menetapkan nilai untuk variabel USAGE juga. Jadi jawaban Anda sama persis. :)
Bunyk
1
@deej Dari spec POSIX : Dokumen-di sini ... berlanjut hingga ada garis yang hanya berisi pembatas dan <newline>
Fornost
1
@Fornost Tidak bertentangan dengan apa yang saya katakan
deej
84

echomenambahkan spasi di antara argumen yang diteruskan ke sana. $textdikenakan ekspansi variabel dan pemisahan kata, sehingga echoperintah Anda setara dengan:

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

Anda dapat melihat bahwa spasi akan ditambahkan sebelum "ini". Anda dapat menghapus karakter baris baru, dan mengutip $textuntuk mempertahankan baris baru:

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

echo "$text" > filename

Atau Anda bisa menggunakan printf, yang lebih kuat dan portabel daripada echo:

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

Di bash, yang mendukung ekspansi brace, Anda bahkan dapat melakukan:

printf "%s\n" "this is line "{one,two,three} > filename
Josh Jolly
sumber
1
Terima kasih telah menjelaskan mengapa mod melihat ruang ekstra saat menggunakan perintah "echo". Jawaban ini juga berfungsi dengan baik ketika menggunakan skrip bash (tidak seperti sesi shell interaktif). Merasa seperti ini adalah jawaban yang nyata dan harus menjadi jawaban yang diterima.
onelaview
1
Ini harus diterima jawaban. Semua jawaban lain memberikan banyak cara lain yang menarik untuk mengatasi rasa sakit OP, tetapi secara teknis pertanyaannya adalah "bagaimana ruang ekstra keluar" dan tidak ada yang membahas ini :-) !!! Terima kasih, Josh untuk membuat -1 misteri!
Dmitry Shevkoplyas
45

dalam skrip bash bekerja sebagai berikut:

#!/bin/sh

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

kalau tidak:

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

nama file kucing memberi:

this is line one
this is line two
this is line three
Chris Maes
sumber
Tampaknya trik alternatif berfungsi saat Shell Script tetapi tampaknya tidak bekerja untuk bash.
Macindows
3
@ Macindows Sepertinya saya sudah lupa -eopsi untuk echo. Silakan coba lagi.
Chris Maes
41

Saya telah menemukan lebih banyak solusi karena saya ingin setiap baris diindentasi dengan benar:

  1. Anda dapat menggunakan echo:

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

    Ini tidak berfungsi jika Anda meletakkan "\n"sebelum \di ujung baris.

  2. Atau, Anda dapat menggunakan printfuntuk portabilitas yang lebih baik (saya kebetulan memiliki banyak masalah dengan echo):

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
  3. Namun solusi lain mungkin:

    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

    atau

    text=''
    text+="this is line one\n"
    text+="this is line two\n"
    text+="this is line three\n"
    printf "%b" "$text" > filename
  4. Solusi lain dicapai dengan mencampur printfdan sed.

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

    Tidak mudah untuk memperbaiki kode yang diformat seperti ini saat Anda memasukkan kode indentasi ke dalam kode.

  5. Dimungkinkan untuk menggunakan fungsi pembantu dan beberapa trik substitusi variabel:

    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"
Mateusz Piotrowski
sumber
3b adalah solusi pilihan saya ketika ingin mempertahankan indentasi kode dan indentasi string secara independen, setidaknya ketika saya tidak dapat menggunakan 2 dalam penugasan variabel, dan lebih mudah dibaca daripada 3a. Ketika saya tidak peduli, saya hanya membiarkan string yang dikutip terbuka pada beberapa baris.
Pysis
Jawaban yang sangat bagus terutama 3b
Sumit Trehan
"Tidak berfungsi jika Anda meletakkan" \ n "tepat sebelum \ di akhir baris." - adalah tip yang bagus saat menggunakan gema.
Noam Manos
6

Berikut ini adalah cara yang saya sukai untuk menetapkan string multi-line ke variabel (saya pikir itu terlihat bagus).

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

String1
String2
String3
...
StringN
_______________________________________________________________________________

Jumlah garis bawah adalah sama (di sini 80) dalam kedua kasus.

Frank-Rene Schäfer
sumber
0

Hanya untuk menyebutkan penggabungan satu baris sederhana karena dapat bermanfaat kadang-kadang.

# 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" 

Anda akan mendapatkan sesuatu seperti ini

batang 
   foo 
 guga 
   puga 

Semua ruang putih utama dan akhir akan dipertahankan dengan benar

echo "$v3" > filename
it3xl
sumber
0

Ada banyak cara untuk melakukannya. Bagi saya, memasukkan string ke dalam sed bisa berfungsi dengan baik.

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"

Jawaban ini didasarkan pada jawaban Mateusz Piotrowski tetapi sedikit disempurnakan.

Beni Trainor
sumber
-1

itu akan berfungsi jika Anda meletakkannya seperti di bawah ini:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
luk
sumber