Linux bash: Penugasan banyak variabel

121

Apakah ada di linux bash sesuatu yang mirip dengan kode berikut di PHP:

list($var1, $var2, $var3) = function_that_returns_a_three_element_array() ;

yaitu Anda menetapkan dalam satu kalimat nilai yang sesuai untuk 3 variabel berbeda.

Katakanlah saya memiliki fungsi bash myBashFuntionyang menulis ke stdout string "qwert asdfg zxcvb". Apakah mungkin melakukan sesuatu seperti:

(var1 var2 var3) = ( `myBashFuntion param1 param2` )

Bagian di sebelah kiri tanda sama dengan bukan sintaks yang valid tentunya. Saya hanya mencoba menjelaskan apa yang saya minta.

Namun, apa yang berhasil adalah sebagai berikut:

array = ( `myBashFuntion param1 param2` )
echo ${array[0]} ${array[1]} ${array[2]}

Tapi array yang diindeks tidak sejelas nama variabel biasa.
Namun, saya hanya bisa melakukan:

var1 = ${array[0]} ; var2 = ${array[1]} ; var3 = ${array[2]}

Tetapi itu adalah 3 pernyataan lagi yang lebih suka saya hindari.

Saya hanya mencari sintaks pintasan. Apa itu mungkin?

Mendapatkan gratis
sumber

Jawaban:

222

Hal pertama yang terlintas di benak saya:

read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"

keluarannya, tidak mengherankan

1|2|3
Michael Krelin - peretas
sumber
4
Apakah ada cara untuk membuat ini berfungsi jika variabel pertama berisi spasi?
Rucent88
7
@Michael Menggunakan read -d "\n" v1 v2 <<<$(cmd)bekerja dengan sempurna. Terima kasih!
Rucent88
1
@LeeNetherton, bagus, meskipun saya tidak yakin apakah seseorang memerlukan status pengembalian perintah echo :-) Saya pikir pada saat menulis jawaban bash yang mendukung sintaks ini kurang umum (seperti yang diinstal secara default), meskipun saya Saya tidak 100% yakin.
Michael Krelin - hacker
4
@ MichaelKrelin-hacker yakin, status kembalian echotidak ada gunanya, tetapi saya menggunakan teknik ini untuk mengembalikan beberapa nilai dari skrip yang saya pedulikan tentang status pengembalian. Saya pikir saya akan membagikan temuan saya.
Lee Netherton
1
Untuk keamanan, Anda harus menggunakan read -r::do not allow backslashes to escape any characters
Tom Hale
18

Saya ingin menetapkan nilai ke array. Jadi, memperluas pendekatan Michael Krelin , saya melakukan:

read a[{1..3}] <<< $(echo 2 4 6); echo "${a[1]}|${a[2]}|${a[3]}"

yang menghasilkan:

2|4|6 

seperti yang diharapkan.

soundray
sumber
2
Untuk meletakkan nilai-nilai dalam array sudah ada solusi sederhana yang saya sebutkan dalam pertanyaan:a=( $(echo 2 4 6) ) ; echo ${a[0]} ${a[1]} ${a[2]}
GetFree
Ya, saya telah melewatkannya. Saya berpendapat, bahwa saran saya lebih cocok untuk menetapkan array yang lebih besar.
soundray
@soundray Solusi Anda menggunakan ekspansi dan herestring, bash apa adanya, saya ragu itu akan bekerja dengan baik dalam skenario itu (tetapi saya tidak memeriksanya).
Camilo Martin
Untuk keamanan, Anda harus menggunakan read -r::do not allow backslashes to escape any characters
Tom Hale
5

Saya pikir ini mungkin membantu ...

Untuk memecah tanggal yang dimasukkan pengguna (hh / bb / tttt) di skrip saya, saya menyimpan hari, bulan, dan tahun ke dalam array, dan kemudian memasukkan nilainya ke dalam variabel terpisah sebagai berikut:

DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
SDGuero
sumber
Mengapa tidak menghindari 4 subkulit ditambah proses sed ekstra, dan lakukan semua itu dalam satu baris:IFS=/ read -r m d y < <(echo 12/29/2009)
Amit Naidu
5

Terkadang Anda harus melakukan sesuatu yang funky. Katakanlah Anda ingin membaca dari sebuah perintah (contoh tanggal oleh SDGuero misalnya) tetapi Anda ingin menghindari banyak percabangan.

read month day year << DATE_COMMAND
 $(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year

Anda juga bisa menyalurkan ke perintah read, tetapi kemudian Anda harus menggunakan variabel dalam subkulit:

day=n/a; month=n/a; year=n/a
date "+%d %m %Y" | { read day month year ; echo $day $month $year; }
echo $day $month $year

menghasilkan ...

13 08 2013
n/a n/a n/a
Otheus
sumber
The readperintah tidak terjadi di subkulit karena kawat gigi, itu karena Anda punya perintah membaca di sisi kanan pipa. Anda perlu menjalankan readperintah di shell saat ini, yang dapat Anda lakukan sepertiread day month year <<< `date "+%d %m %Y"`
pneumatik
Tidak - read terjadi tetapi cakupan variabel yang dibaca berada di luar cakupan saat subkulit pipeline berakhir.
Otheus
1
Komentar saya adalah tentang alasan mengapa pembacaan terjadi di subkulit, dan saya menyadari sekarang saya salah membaca apa yang Anda tulis. Saya pikir Anda bermaksud bahwa subkulit dibuat karena Anda menggunakan tanda kurung kurawal di sekitar pernyataan gabungan. Tapi! Alasan Anda memberikan contoh itu adalah untuk menghindari garpu, dan bukankah garpu subkulit juga?
pneumatik
Contoh pertama membutuhkan tepat satu percabangan: sehingga bash dapat meluncurkan perintah tanggal. Dalam contoh kedua, Anda menyiapkan pipeline antara tanggal dan sub-shell Anda. Saya pikir bash hari ini cukup pintar untuk tidak benar-benar masuk ke subkulit, tapi saya tidak yakin tentang itu. Bagaimanapun, sepertinya itu akan terjadi :)
Otheus
0

Bab 5 dari Bash Cookbook oleh O'Reilly, membahas (secara panjang lebar) alasan persyaratan dalam tugas variabel bahwa tidak ada spasi di sekitar tanda '='

MYVAR="something"

Penjelasannya ada hubungannya dengan membedakan antara nama perintah dan variabel (di mana '=' mungkin argumen yang valid).

Ini semua tampaknya sedikit seperti membenarkan setelah kejadian, tetapi dalam kasus apa pun tidak ada penyebutan metode untuk menetapkan daftar variabel.

pavium
sumber
Ya saya tahu. Saya baru saja menambahkan spasi ekstra di sana-sini agar mudah dibaca
GetFree
Memang itu motivasi yang buruk: Bagaimana jika ' ;' adalah argumen yang valid? Ketika saya menulis ls ; cditu masih panggilanls dan cdmeskipun ada spasi. Jika saya ingin membuat daftar direktori yang dipanggil ;dan cdsaya bisa mengetik ls ';' cd.
PieterNuyts