Cara menambahkan baris baru ke dalam variabel dalam skrip bash


Jawaban:


73

Di dalamnya bashAnda bisa menggunakan sintaks

str=$'Hello World\n===========\n'

Kutipan tunggal yang didahului oleh a $adalah sintaks baru yang memungkinkan untuk memasukkan urutan escape dalam string.

printfBuiltin juga memungkinkan untuk menyimpan output yang dihasilkan ke variabel

printf -v str 'Hello World\n===========\n'

Kedua solusi tidak memerlukan subkulit.

Jika dalam hal-hal berikut Anda perlu mencetak string, Anda harus menggunakan tanda kutip ganda, seperti dalam contoh berikut:

echo "$str"

karena ketika Anda mencetak string tanpa tanda kutip, baris baru dikonversi menjadi spasi.


1
Apa yang str=$'Hello World\n===========\n'disebut sintaksis ? substitusi variabel?
zengr

5
@ zengr: Ini disebut kutipan ANSI-C , dan juga didukung di zshdan ksh; namun, ini BUKAN sesuai POSIX.
mklement0

4
@ mkelement0, ini berasal dari ksh93, juga didukung oleh zsh, bash, mksh dan FreeBSD sh, dan dimasukkannya dalam revisi utama berikutnya dari POSIX sedang dalam diskusi
Stéphane Chazelas

1
Tampaknya tidak bekerja dengan tanda kutip ganda? misalnya str=$"My $PET eats:\n$PET food"? Pendekatan ini bekerja untuk tanda kutip ganda
Brad Parks

31

Anda dapat menempatkan baris baru literal dalam tanda kutip tunggal (di shell gaya Bourne / POSIX).

str='Hello World
===========
'

Untuk string multiline, di sini dokumen sering kali nyaman. String diumpankan sebagai input ke perintah.

mycommand <<'EOF'
Hello World
===========
EOF

Jika Anda ingin menyimpan string dalam suatu variabel, gunakan catperintah dalam substitusi perintah. Karakter baris baru di akhir string akan dilucuti oleh substitusi perintah. Jika Anda ingin mempertahankan baris baru, letakkan sumbat di ujungnya dan cabut kemudian. Di shell yang sesuai dengan POSIX, Anda dapat menulis str=$(cat <<'EOF'); str=${str%a}diikuti oleh heredoc yang tepat, tetapi bash membutuhkan heredoc untuk muncul sebelum tanda kurung penutup.

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

Di ksh, bash, dan zsh, Anda dapat menggunakan $'…'formulir yang dikutip untuk memperluas garis miring terbalik di dalam tanda kutip.

str=$'Hello World\n===========\n'

1
Saya menggunakan GNU bash 4.1.5, dan str=$(cat <<'EOF')tidak berfungsi sebagaimana mestinya .. )Kebutuhan untuk ditempatkan pada baris berikutnya setelah akhir-dok EOF.. tetapi meskipun demikian, ia kehilangan baris tambahan karena Command Pengganti.
Peter.O

@ Fred Poin bagus, saya sudah menjelaskan tentang baris baru dan kode yang ditampilkan yang bekerja di bash. Saya pikir ini adalah bug dalam bash, meskipun jujur ​​saat membaca ulang spesifikasi POSIX, saya merasa tidak jelas bahwa perilakunya diamanatkan ketika << ada di dalam substitusi perintah dan heredoc tidak.
Gilles 'SO- stop being evil'

Hal-hal hebat; untuk melestarikan trailing (dan memimpin) \ninstance bashketika mengambil-doc di sini dalam variabel, pertimbangkan IFS= read -r -d '' str <<'EOF'...sebagai alternatif untuk pendekatan stopper (lihat jawaban saya).
mklement0

8

Apakah Anda menggunakan "gema"? Coba "echo -e".

echo -e "Hello World\n===========\n"

2
BTW. Anda tidak memerlukan final \ n, karena echoakan secara otomatis menambahkannya, kecuali jika Anda menentukan -n. (Namun, beban utama dari pertanyaan, adalah bagaimana memasukkan baris baru ini ke dalam variabel).
Peter.O

+1 Dari semua solusi, yang ini paling langsung dan paling sederhana.
Hai Vu

echo -e tidak berfungsi di OS X
Greg M. Krsak

2
@GregKrsak: Dalam bash, echo -e tidak bekerja pada OS X - itu karena echomerupakan bash builtin (bukan executable eksternal) dan bahwa builtin tidak mendukung -e. (Sebagai bawaan, itu harus bekerja pada semua platform yang dijalankan bash; secara kebetulan, echo -ebekerja di dalam kshdan zshjuga). Sebaliknya, utilitas eksternalecho pada OS X - /bin/echo- memang tidak mendukung -e.
mklement0

4

Jika Anda membutuhkan baris baru dalam skrip Anda berkali-kali, Anda bisa mendeklarasikan variabel global yang memegang baris baru. Dengan begitu Anda bisa menggunakannya dalam string yang dikutip ganda (ekspansi variabel).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"

Mengapa $''perlu subkulit?
Mat

Maaf, saya salah membaca jawaban.
pihentagy

Bisakah saya meminta penjelasan dari downvoters?
pihentagy

Bagus! Ini dapat dimasukkan dalam variabel menggunakan tanda kutip ganda, misalnya"My dog eats:${NL}dog food"
Brad Parks

Ini berhasil untuk saya. Saat menggunakan skrip bash untuk menggabungkan string yang secara otomatis disalin ke clipboard untuk ditempelkan di tempat lain, pendekatan ini bekerja untuk menambahkan baris baru pada hasil yang dihasilkan.
Ville

3

Dari semua diskusi, berikut adalah cara paling sederhana bagi saya:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

The gema perintah harus menggunakan tanda kutip ganda .


3

Untuk melengkapi jawaban hebat yang sudah ada:

Jika Anda menggunakan bashdan lebih suka menggunakan baris baru untuk keterbacaan , readadalah opsi lain untuk menangkap dokumen di sini dalam variabel , yang (seperti solusi lain di sini) tidak memerlukan penggunaan subkulit.

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rmemastikan bahwa readtidak menginterpretasikan input (secara default, itu akan memperlakukan backslash khusus, tetapi itu jarang diperlukan).

  • -d ''menetapkan pembatas "record" menjadi string kosong, menyebabkan readpembacaan seluruh input sekaligus (bukan hanya satu baris).

Perhatikan bahwa dengan meninggalkan $IFS(pemisah bidang internal) pada pengaturan standarnya, $' \t\n'(spasi, tab, baris baru), spasi spasi apa pun yang memimpin dan tertinggal dipangkas dari nilai yang ditetapkan $str, yang mencakup baris baru di sini-doc.
(Perhatikan bahwa meskipun tubuh di sini-doc mulai pada baris setelah pembatas mulai (di 'EOF'sini), itu tidak mengandung baris baru yang memimpin ).

Biasanya, ini adalah perilaku yang diinginkan, tetapi jika Anda ingin yang mengikuti baris baru, gunakan IFS= read -r -d ''bukan hanya read -r -d '', tetapi perhatikan bahwa spasi spasi apa pun yang memimpin dan tertinggal kemudian dipertahankan.
(Perhatikan bahwa menambahkan IFS= langsung ke readperintah berarti bahwa penugasan hanya berlaku selama perintah itu saja, sehingga tidak perlu mengembalikan nilai sebelumnya.)


Menggunakan dokumen-sini juga memungkinkan Anda untuk menggunakan indentasi opsional untuk mematikan string multiline agar mudah dibaca:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

Menempatkan di -antara <<dan pembuka di sini-doc pembatas ( 'EOF', di sini) menyebabkan karakter tab utama dihapus dari badan di sini-doc dan bahkan pembatas penutup, tetapi perlu dicatat bahwa ini hanya bekerja dengan karakter tab yang sebenarnya , bukan spasi, jadi jika Anda Editor menerjemahkan penekanan tombol tab ke spasi, diperlukan kerja ekstra.


-1

Anda perlu melakukannya dengan cara ini:

STR=$(echo -ne "Hello World\n===========\n")

Memperbarui:

Seperti yang ditunjukkan Fred, dengan cara ini Anda akan kehilangan jejak "\ n". Untuk menetapkan variabel dengan urutan backslash diperluas, lakukan:

STR=$'Hello World\n===========\n\n'

mari kita mengujinya:

echo "[[$STR]]"

beri kami sekarang:

[[Hello World
===========

]]

Perhatikan, bahwa $ '' berbeda dari $ "". Yang kedua melakukan terjemahan sesuai dengan lokal saat ini. Untuk deital, lihat bagian QUOTING di man bash.


-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

keluaran:

FOO
BAR

FOO
BAR

1
Kenapa tidak sederhana saja result+=$foo$'\n'? $(printf %s "$foo")akan memangkas trailing karakter baris baru $foojika ada.
Stéphane Chazelas

Tidak ada penjelasan untuk kodenya, kalau tidak, itu tidak masalah bagi saya.
somethingSomething
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.