Apa cara yang paling benar untuk melewatkan array ke suatu fungsi?


8

Anggap saya memiliki array yang sangat besar $large_list, adakah cara untuk menulis fungsi yang akan menggunakan array sebagai argumen? Sebagai contoh:

echo_idx_array () {
    arr="$1"
    idx="$2"

    echo "${arr[$idx]}"
}

Apa strategi yang biasa dilakukan untuk melakukan hal seperti itu? Saya mencoba memberikan variabel $large_listtetapi itu kosong.

Saya bersedia mengubah fungsi untuk menyesuaikannya dengan perubahan apa pun dalam daftar argumen.

Sebagai catatan, saya menggunakan ksh88, dan saya mencari jawaban yang portabel.


EDIT : Sejauh ini yang terbaik yang bisa saya lakukan adalah untuk loop melalui array dan mengirim setiap elemen sebagai argumen ke fungsi. Ini tampaknya sangat jelek dan rawan kesalahan, belum lagi pasti akan mencapai batas tertentu dengan cepat. Inilah yang saya lakukan:

foo () {
    echo $*
}

cmd="foo "
while [[ $i -lt $MAX_ARR_SIZE ]]; do
    cmd="$cmd ${large_list[$i]}"
    ((i=i+1))
done

eval $cmd

Apakah tidak ada yang lebih baik untuk dilakukan?


1
Saya tidak terbiasa dengan ksh88, tetapi jika Anda harus melewatkan seluruh array dengan nilai, sudahkah Anda mencobanya func "${array[@]}"? Jika Anda hanya perlu melewati satu elemen, cukup lewat elemen - tidak perlu membuatnya lebih berbelit-belit dengan melewatkan array dan indeks.
jw013

Saya mencoba sintaks yang Anda sarankan, tetapi tidak berhasil :(
rahmu

1
Saya lelah dan bingung. Saya sudah mencoba "${array[$@]}. Saran Anda benar-benar berfungsi. MEA Culpa.
rahmu

Jawaban:


10

Untuk meneruskan elemen array sebagai argumen ke fungsi, gunakan sintaks ksh untuk memperluas elemen array sebagai daftar.

work_on_array "${myarray[@]}"

The [@]akhiran membuat ini ekspansi larik. Kutipan ganda melindungi setiap elemen dari ekspansi lebih lanjut (pemisahan dan globbing). Hasil ekspansi tidak secara umum satu kata seperti biasanya dengan tanda kutip ganda, tetapi kata-kata sebanyak elemen dalam array.

The N th elemen dari array kemudian . Untuk mengaksesnya, Anda perlu menggunakan ; lihat Menggunakan referensi variabel "di dalam" variabel lain${N}eval


Terima kasih. Pertanyaan: jika hasil ekspansi bukan satu kata, mengapa kutipan perlu? Bisakah mereka dihilangkan? Apakah Anda hanya menerapkan saran Anda "selalu mengutip kecuali Anda memiliki alasan yang baik untuk tidak"? : p
rahmu

1
@rahmu Kutipan diperlukan untuk menghindari pemisahan dan penggumpalan pada elemen individual. Pertimbangkan myarray=("hello world" wibble)(2 elemen, yang pertama berisi spasi): work_on_array "${myarray[@]}"melewati 2 parameter hello worlddan wibble; work_on_array ${myarray[@]}melewati 2 parameter hello, worlddan wibble. Dan dengan myarray=(*), work_on_array ${myarray[@]}melewati daftar file di direktori saat ini. (Karenanya ini adalah salah satu dari banyak kasus di mana saran saya membuat perbedaan praktis.)
Gilles 'SO- stop being evil'

Koreksi saya jika saya salah, tapi saya percaya ada kesalahan ketik pada apa yang Anda tulis: ekspansi tanda kutip melewati 3 params, bukan 2.
rahmu

1
@rahmu Ada dua parameter: ketakutan dan kejutan ... dan efisiensi yang kejam. (Dengan kata lain, Anda benar, ada kesalahan ketik: hello, worlddan wibblemembuat 3 parameter.)
Gilles 'SO berhenti menjadi jahat'

4

Ada cara di bash 4.3+, yang mungkin berasal dari ksh:

echo_idx_array () # array index
{
    local -n array=$1     # add nameref attribute
    local idx=$2
    echo "${array[idx]}"
}

$ names=(one two three four)
$ echo_idx_array names 2
three
$ days=([monday]=eggs [tuesday]=bread [sunday]=jam)    # associative array
$ echo_idx_array days sunday
jam

Lihat juga declare -n.


Hah, menarik. Ya, ini berasal dari ksh, dan bekerja di mksh tidak dimodifikasi.
mirabilos

1

Tergantung pada Korn Shell ... AT&T ksh93 dan mksh versi terbaru mendukung ini:

function echo_idx_array {
    nameref arr=$1
    idx=$2

    echo "${arr[idx]}"
}

set -A test -- a b c
echo_idx_array test 1

Dalam shell saya saat ini, ini tidak menghasilkan "b".

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.