Cara menambahkan baris baru ke dalam variabel dalam skrip bash

64

Kapan saya melakukannya

str="Hello World\n===========\n"

Saya juga \nmencetaknya. Bagaimana saya bisa mendapatkan baris baru?

Jiew Meng
sumber
1
Meskipun jawaban di sini bagus, pada kenyataannya saya pikir Anda akan lebih baik menggunakan array untuk hal semacam ini sebagian besar waktu.
evilsoup
Lihat juga pertanyaan Mencoba menanamkan baris baru dalam variabel dalam bash .
HelloGoodbye

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.

enzotib
sumber
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'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
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"
Mike
sumber
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}"
pihentagy
sumber
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 .

kholis
sumber
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.

mklement0
sumber
-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.

Michał Šrajer
sumber
-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
vern
sumber
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