Bagaimana cara membaca beberapa baris dari STDIN ke dalam variabel?

24

Saya sudah googling pertanyaan ini tidak berhasil. Saya mengotomatiskan proses pembuatan di sini di tempat kerja, dan semua yang saya coba lakukan adalah mendapatkan nomor versi dan deskripsi kecil dari bangunan yang mungkin multi-line. Sistem yang digunakan ini adalah OSX 10.6.8.

Saya telah melihat semuanya mulai dari menggunakan CAT hingga memproses setiap baris seperlunya. Saya tidak tahu apa yang harus saya gunakan dan mengapa.

Mencoba

read -d '' versionNotes

Menghasilkan input yang kacau jika pengguna harus menggunakan kunci backspace. Juga tidak ada cara yang baik untuk menghentikan input karena ^ D tidak berhenti dan ^ C hanya keluar dari proses.

read -d 'END' versionNotes

Berfungsi ... tetapi input input masih rusak jika tombol backspace diperlukan.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Tidak mengakhiri input dengan benar (karena saya terlambat mencari yang cocok dengan string kosong).

Robert K.
sumber
Anda mendapatkan informasi ini dari pengguna, benar?
glenn jackman
Benar; Saya ingin pengguna memasukkan informasi ini di terminal ketika menjalankan skrip.
Robert K
1
Anda belum membuat diri Anda jelas, saya lebih suka mengatakan.
poige

Jawaban:

20

man bash menyebutkan «...

Substitusi perintah $ (file cat) dapat diganti dengan yang setara tetapi lebih cepat $ (<file).

... »

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

dan saya setuju ini layak disebut - echo "$myVar"akan menampilkan input seperti yang diberikan.

poige
sumber
1
Bagaimana cara berhenti setelah input multiline? Jika saya menekan Ctrl C berhenti tetapi variabel tidak disimpan!
Nikhil
2
Terminal UNIX® memiliki "disiplin": en.wikipedia.org/wiki/Line_discipline • Periksa apa artinya "eof" • Bacalah man stty, cari tahu bagaimana mendapatkan pengaturan saat ini
poige
2
ctrl-d untuk berhenti.
freb
9

Coba ini:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Tanpa jeda baris:

user@host:~$ echo $x
mic check one two

Dengan jeda baris:

user@host:~$ echo "$x"
mic
check
one
two
suara-suara
sumber
2
-d ''persis apa yang saya butuhkan. Terima kasih
Bruno Bronosky
@Bruno Dengan senang hati; itu rumit. Terutama pada pandangan pertama, tampilannya cukup standar. Namun bisa sangat berguna, setelah Anda memahami berbagai keanehan.
Suara
2

Saya telah memecahkan masalah ini dengan menangani setiap baris sampai saya menemukan baris kosong. Ini cukup berhasil untuk situasi saya. Tetapi jika seseorang ingin menambahkan solusi yang lebih baik, jangan ragu untuk melakukannya.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done
Robert K.
sumber
Gunakan read -rsebagai gantinya.
adaptr
2

Anda dapat memulai editor seperti vim, pico ...

${VISUAL:-${EDITOR:-vi}} source/application.yml
Mircea Vutcovici
sumber
Um ... bagaimana itu menjawab pertanyaan OP dengan cara apa pun?
adaptr
Dia dapat memulai editor dari skrip.
Mircea Vutcovici
Dan itu mencapai apa, tepatnya? Dia ingin menggunakan teks dari file dalam skrip, bukan menulis informasi ke file.
adaptr
Dia tidak dapat membaca teks dari pengguna dan menulisnya ke file. Silakan baca komentar yang ditambahkan ke pertanyaan.
Mircea Vutcovici
1

Pertama beberapa koreksi:

  1. Untuk mengizinkan "edisi" pada penggunaan baris -eyang menggunakan readline (sehingga Anda memiliki riwayat bash dan semua fitur pengeditan)
  2. -dhanya membutuhkan satu karakter. Misal dari 'END' mengambil 'E' dan setiap kali pengguna menulis 'E' pembacaan berhenti (saya kira itu bukan yang Anda inginkan ...)

Ada beberapa kemungkinan untuk melakukan ini. Saya akan membaca baris demi baris dan berhenti ketika baris kosong ditemukan (meskipun Anda dapat menyetel kata berhenti):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done
estani
sumber
0

Anda memiliki beberapa metode.

Salah satu metode paling sederhana adalah:

MYVAR=$(yourcommand)
echo $"MYVAR"

Sebagai contoh:

MYVAR=$(ls /)
echo $"MYVAR"
SCHITS Bertrand
sumber
Kecuali saya tidak menjalankan perintah shell seperti LS. Saya meminta input multi-line dari pengguna.
Robert K
Ini adalah praktik yang sangat buruk; jangan memproses output ls!
adaptr
@adaptr Kami telah mendengar semuanya sebelumnya, maukah Anda menyarankan alternatif yang baik?
Suara
0

Kami menggunakan konstruksi menggunakan xargs dan ctrl-d untuk memecah. Saya tidak sepenuhnya puas dengan itu, tetapi tentu saja pekerjaan mengambil input multi-line pengguna dan memasukkannya ke dalam variabel (format utuh). (Tugas pertama dan ketiga menambahkan tanda kutip di sekitar isi input xargs.)

    printf "\\033[1mWhen finished hit ctrl-d on a new line to proceed.\\033[0m  \\n\\n" 
    # this will load the user's input into a variable instead of a file 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

Kami menggunakan reminderBody sebagai subjek email yang dikirim melalui surat (via bash).

JamesIsIn
sumber
-1

Lihat: http://tldp.org/LDP/abs/html/internal.html#READR

Gunakan readdan perhatikan bahwa jika Anda mengakhiri baris dengan \baris baru diabaikan. Jadi Anda bisa melakukan:

#! / bin / bash

baca -p "versi:" versi
echo $ version

# masukkan beberapa input dan akhiri baris panjang dengan "\", lalu masukkan polos di akhir
baca -p "deskripsi:" deskripsi
echo -e "$ version \ n $ description >> yourfile.txt
Kindjal
sumber
Jika saya hanya ingin paragraf dengan jeda baris diabaikan, ya. Tetapi karena ini adalah daftar catatan rilis yang dihasilkan untuk skrip build, saya harus dapat mempertahankan jeda baris tersebut; Saya mungkin mencoba memasukkan daftar berpoin, misalnya.
Robert K
ABS adalah keburukan proporsi mengerikan. 90% dari itu jelas salah.
adaptr
Ini bukan yang buruk.
Suara