Bagaimana saya bisa melewatkan array sebagai parameter ke fungsi bash?
Catatan: Setelah tidak menemukan jawaban di sini di Stack Overflow, saya memposting solusi yang agak kasar sendiri. Ini memungkinkan hanya satu array yang diteruskan, dan itu menjadi elemen terakhir dari daftar parameter. Sebenarnya, ia tidak melewatkan array sama sekali, tetapi daftar elemen-elemennya, yang dirakit kembali menjadi array dengan dipanggil_fungsi (), tetapi berhasil bagi saya. Jika seseorang tahu cara yang lebih baik, silakan menambahkannya di sini.
Jawaban:
Anda dapat melewati beberapa array sebagai argumen menggunakan sesuatu seperti ini:
akan bergema:
Edit / catatan: (dari komentar di bawah)
descTable
danoptsTable
diteruskan sebagai nama dan diperluas dalam fungsi. Jadi tidak$
diperlukan ketika diberikan sebagai parameter.descTable
dll yang ditentukanlocal
, karena penduduk setempat terlihat oleh fungsi yang mereka panggil.!
dalam${!1}
memperluas variabel arg 1.declare -a
hanya membuat array yang diindeks eksplisit, itu tidak sepenuhnya diperlukan.sumber
Catatan: Ini adalah solusi yang agak kasar yang saya posting sendiri, setelah tidak menemukan jawaban di Stack Overflow. Ini memungkinkan hanya satu array yang diteruskan, dan itu menjadi elemen terakhir dari daftar parameter. Sebenarnya, ia tidak melewatkan array sama sekali, tetapi daftar elemen-elemennya, yang dirakit kembali menjadi array dengan dipanggil_fungsi (), tetapi berhasil bagi saya. Agak kemudian Ken memposting solusinya, tetapi saya menyimpan milik saya di sini untuk referensi "bersejarah".
Ditingkatkan oleh TheBonsai, terima kasih.
sumber
called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"
dll ... masih dengan beberapa batasan yang jelas, tetapi benar-benar, lebih baik untuk menyelesaikan masalah dengan cara yang didukung bahasa, daripada mencoba membengkokkan bahasa agar berfungsi seperti yang biasa Anda lakukan dalam bahasa lain.Mengomentari solusi Ken Bertelson dan menjawab Jan Hettich:
Bagaimana itu bekerja
fungsi
takes_ary_as_arg descTable[@] optsTable[@]
baristry_with_local_arys()
mengirimkan:descTable
danoptsTable
yang dapat diakses olehtakes_ary_as_arg
fungsi.takes_ary_as_arg()
fungsi menerimadescTable[@]
danoptsTable[@]
sebagai string, itu berarti$1 == descTable[@]
dan$2 == optsTable[@]
.di awal
takes_ary_as_arg()
fungsi menggunakan${!parameter}
sintaks, yang disebut referensi tidak langsung atau kadang-kadang dua direferensikan , ini berarti bahwa alih-alih menggunakan$1
's nilai, kita menggunakan nilai diperluas nilai$1
, misalnya:begitu juga untuk
$2
.argAry1=("${!1}")
menciptakanargAry1
sebagai array (tanda kurung=
) dengan diperluasdescTable[@]
, seperti menulis di sanaargAry1=("${descTable[@]}")
secara langsung. dideclare
sana tidak diperlukan.NB: Perlu disebutkan bahwa inisialisasi array menggunakan bentuk braket ini menginisialisasi array baru sesuai dengan
IFS
atau Pemisah Bidang Internal yang secara default tab , baris baru dan ruang . dalam hal itu, karena[@]
notasi yang digunakan masing-masing elemen dilihat dengan sendirinya seolah-olah ia dikutip (bertentangan dengan[*]
).Reservasi saya dengan itu
Dalam
BASH
, ruang lingkup variabel lokal adalah fungsi saat ini dan setiap fungsi anak dipanggil darinya, ini berarti fakta bahwatakes_ary_as_arg()
fungsi "melihat" merekadescTable[@]
danoptsTable[@]
array, sehingga berfungsi (lihat penjelasan di atas).Karena itu, mengapa tidak langsung melihat variabel-variabel itu sendiri? Sama seperti menulis di sana:
Lihat penjelasan di atas, yang hanya menyalin
descTable[@]
nilai array menurut arusIFS
.Singkatnya
Saya juga ingin menekankan komentar Dennis Williamson di atas: array jarang (array tanpa semua kunci mendefinisikan - dengan "lubang" di dalamnya) tidak akan berfungsi seperti yang diharapkan - kita akan kehilangan kunci dan "menyingkat" array.
Yang sedang berkata, saya memang melihat nilai untuk generalisasi, fungsi sehingga bisa mendapatkan array (atau salinan) tanpa mengetahui nama-nama:
untuk salinan asli: kita dapat menggunakan eval untuk kunci, misalnya:
dan kemudian loop menggunakannya untuk membuat salinan. Catatan: di sini
!
tidak digunakan sebelumnya tidak langsung / evaluasi ganda, melainkan dalam konteks array mengembalikan indeks array (kunci).descTable
danoptsTable
string (tanpa[@]
), kita bisa menggunakan array itu sendiri (seperti dalam referensi) denganeval
. untuk fungsi generik yang menerima array.sumber
Array1
, lalu denganArray2
, melewati nama array menjadi berguna.Masalah mendasar di sini adalah bahwa pengembang bash (s) yang mendesain / mengimplementasikan array benar-benar mengacaukan anjing tersebut. Mereka memutuskan
${array}
itu hanya ulah${array[0]}
, yang merupakan kesalahan buruk. Terutama ketika Anda menganggap itu${array[0]}
tidak memiliki arti dan mengevaluasi ke string kosong jika tipe array asosiatif.Menetapkan array mengambil bentuk di
array=(value1 ... valueN)
mana nilai memiliki sintaks[subscript]=string
, sehingga menetapkan nilai langsung ke indeks tertentu dalam array. Ini membuatnya jadi bisa ada dua jenis array, diindeks secara numerik dan hash diindeks (disebut asosiatif array dalam bahasa bash). Itu juga membuatnya sehingga Anda dapat membuat array diindeks numerik jarang. Meninggalkan[subscript]=
bagian adalah tangan pendek untuk array yang diindeks secara numerik, dimulai dengan indeks ordinal 0 dan bertambah dengan setiap nilai baru dalam pernyataan penugasan.Karena itu,
${array}
harus mengevaluasi ke seluruh array, indeks, dan semua. Ini harus mengevaluasi kebalikan dari pernyataan penugasan. Setiap tahun ketiga CS mayor harus tahu itu. Dalam hal ini, kode ini akan berfungsi persis seperti yang Anda harapkan:Kemudian, meneruskan array dengan nilai ke fungsi dan menugaskan satu array ke array yang lain akan berfungsi sebagai perintah shell lainnya. Tetapi karena mereka tidak melakukan ini dengan benar, operator penugasan
=
tidak bekerja untuk array, dan array tidak dapat diteruskan oleh nilai ke fungsi atau ke subshell atau output secara umum (echo ${array}
) tanpa kode untuk mengunyah semuanya.Jadi, jika itu dilakukan dengan benar, maka contoh berikut akan menunjukkan bagaimana kegunaan array di bash bisa jauh lebih baik:
output yang dihasilkan harus:
Kemudian, array dapat menggunakan operator penugasan, dan diteruskan oleh nilai ke fungsi dan bahkan skrip shell lainnya. Mudah disimpan dengan mengeluarkan ke file, dan dengan mudah dimuat dari file ke dalam skrip.
Sayangnya, kami telah dikecewakan oleh tim pengembang pesta superlatif.
Dengan demikian, untuk meneruskan array ke suatu fungsi, sebenarnya hanya ada satu opsi, dan itu adalah menggunakan fitur nameref:
akan menghasilkan output berikut:
Karena ini lewat referensi, Anda juga dapat menetapkan ke array dalam fungsi. Ya, array yang direferensikan harus memiliki cakupan global, tetapi itu tidak boleh terlalu besar, mengingat ini adalah skrip shell. Untuk meneruskan array indeks asosiatif atau jarang menurut nilai ke suatu fungsi, perlu membuang semua indeks dan nilai ke daftar argumen (tidak terlalu berguna jika array besar) sebagai string tunggal seperti ini:
dan kemudian menulis banyak kode di dalam fungsi untuk memasang kembali array.
sumber
local -n
lebih baik dan lebih terkini daripada jawaban yang diterima. Solusi ini juga akan berfungsi untuk variabel jenis apa pun. Contoh yang tercantum dalam jawaban ini dapat disingkat menjadilocal -n ARR=${1}
. Namun-n
opsi untuklocal
/declare
hanya tersedia di Bash versi 4.3 dan di atasnya.funky ARR
), shell akan memberikan peringatancircular name reference
, karena pada dasarnya fungsi akan mencoba melakukannyalocal -n ARR=ARR
. Diskusi yang bagus tentang topik ini.Jawaban DevSolar memiliki satu poin yang saya tidak mengerti (mungkin dia memiliki alasan khusus untuk melakukannya, tetapi saya tidak dapat memikirkannya): Dia mengatur array dari elemen parameter posisi dengan elemen, berulang.
Pendekatan yang lebih mudah adalah
sumber
Contoh
sumber
Cara mudah untuk melewatkan beberapa array sebagai parameter adalah dengan menggunakan string yang dipisahkan karakter. Anda dapat memanggil skrip Anda seperti ini:
Kemudian, Anda dapat mengekstraknya dalam kode Anda seperti ini:
Dengan cara ini, Anda dapat benar-benar melewati beberapa larik sebagai parameter dan tidak harus menjadi parameter terakhir.
sumber
Ini berfungsi bahkan dengan spasi:
sumber
Dengan beberapa trik, Anda dapat benar-benar mengirimkan parameter bernama ke fungsi, bersama dengan array.
Metode yang saya kembangkan memungkinkan Anda untuk mengakses parameter yang dikirimkan ke fungsi seperti ini:
Dengan kata lain, tidak hanya Anda dapat memanggil parameter Anda dengan nama mereka (yang merupakan inti yang lebih mudah dibaca), Anda sebenarnya dapat melewatkan array (dan referensi ke variabel - fitur ini hanya bekerja di bash 4.3)! Plus, variabel yang dipetakan semuanya dalam lingkup lokal, sama seperti $ 1 (dan lainnya).
Kode yang membuat pekerjaan ini cukup ringan dan berfungsi baik di bash 3 dan bash 4 (ini adalah satu-satunya versi yang telah saya uji dengan). Jika Anda tertarik dengan lebih banyak trik seperti ini yang membuat pengembangan dengan bash jauh lebih baik dan lebih mudah, Anda dapat melihat pada Bash Infinity Framework saya , kode di bawah ini dikembangkan untuk tujuan itu.
sumber
Hanya untuk menambah jawaban yang diterima, karena saya menemukan itu tidak berfungsi dengan baik jika isi arraynya seperti:
Dalam hal ini, setiap anggota array akan terpecah, sehingga array yang dilihat fungsinya setara dengan:
Agar case ini berfungsi, cara yang saya temukan adalah dengan meneruskan nama variabel ke fungsi, lalu gunakan eval:
Hanya 2 © saya
sumber
Seburuk itu, berikut adalah solusi yang berfungsi selama Anda tidak melewatkan array secara eksplisit, tetapi variabel yang sesuai dengan array:
Saya yakin seseorang dapat datang dengan implementasi ide yang lebih jelas, tetapi saya telah menemukan ini menjadi solusi yang lebih baik daripada melewati array
"{array[@]"}
dan kemudian mengaksesnya menggunakan internalarray_inside=("$@")
. Ini menjadi rumit ketika ada posisi /getopts
parameter lain. Dalam kasus ini, saya harus terlebih dahulu menentukan dan kemudian menghapus parameter yang tidak terkait dengan array menggunakan beberapa kombinasishift
dan penghapusan elemen array.Perspektif murni cenderung memandang pendekatan ini sebagai pelanggaran bahasa, tetapi secara pragmatis, pendekatan ini telah menyelamatkan saya dari banyak kesedihan. Pada topik terkait, saya juga menggunakan
eval
untuk menetapkan array yang dibangun secara internal ke variabel bernama sesuai dengan parameter yangtarget_varname
saya berikan ke fungsi:eval $target_varname=$"(${array_inside[@]})"
Semoga ini bisa membantu seseorang.
sumber
Persyaratan : Berfungsi untuk menemukan string dalam array.
Ini adalah sedikit penyederhanaan dari solusi DevSolar karena menggunakan argumen yang disahkan daripada menyalinnya.
sumber
Jawaban singkat saya adalah:
${test_array[*]}
dan${test_array2[*]}
harus dikelilingi oleh "", jika tidak Anda akan gagal.sumber