Cách chính xác nhất để truyền một mảng cho một chức năng là gì?


8

Hãy xem xét tôi có một mảng rất lớn $large_list, có cách nào để viết một hàm sẽ lấy mảng đó làm đối số không? Ví dụ:

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

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

Chiến lược thông thường để làm một cái gì đó như thế là gì? Tôi đã thử đưa ra biến $large_listnhưng nó trống rỗng.

Tôi sẵn sàng sửa đổi hàm để điều chỉnh nó theo bất kỳ thay đổi nào trong danh sách đối số.

Đối với hồ sơ, tôi đang sử dụng ksh88 và tôi đang tìm kiếm câu trả lời là có thể mang theo.


EDIT : Cho đến nay, điều tốt nhất tôi có thể đưa ra là lặp qua mảng và gửi từng phần tử làm đối số cho hàm. Điều này có vẻ cực kỳ xấu xí và dễ bị lỗi, chưa kể rằng nó bị ràng buộc để đạt được một số giới hạn một cách nhanh chóng. Đây là những gì tôi đã làm:

foo () {
    echo $*
}

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

eval $cmd

Không có cái gì tốt hơn để làm?


1
Tôi không quen thuộc với ksh88, nhưng nếu bạn cần vượt qua toàn bộ mảng theo giá trị, bạn đã thử func "${array[@]}"chưa? Nếu bạn chỉ cần truyền một phần tử, chỉ cần truyền phần tử - không cần làm cho nó trở nên phức tạp hơn bằng cách truyền một mảng và một chỉ mục.
jw013

Tôi đã thử cú pháp mà bạn đề xuất, nhưng nó không hoạt động :(
rahmu

1
Tôi mệt mỏi và bối rối. Tôi đã thử "${array[$@]}. Đề nghị của bạn thực sự hoạt động. Mea culpa.
rahmu

Câu trả lời:


10

Để truyền các phần tử mảng làm đối số cho hàm, sử dụng cú pháp ksh để mở rộng các phần tử của mảng dưới dạng danh sách.

work_on_array "${myarray[@]}"

Các [@]hậu tố tạo nên một mở rộng mảng. Các dấu ngoặc kép bảo vệ mỗi phần tử khỏi sự mở rộng hơn nữa (tách và tạo khối). Kết quả của việc mở rộng không phải là nói chung một từ như thường là với dấu ngoặc kép, mà là nhiều từ như có các phần tử trong mảng.

Phần tử thứ N của mảng là sau đó . Để truy cập nó, bạn cần sử dụng ; xem Sử dụng một tham chiếu biến "bên trong" một biến khác${N}eval


Cảm ơn. Câu hỏi: nếu kết quả của việc mở rộng không phải là một từ, tại sao các trích dẫn cần thiết? Họ có thể được bỏ qua? Bạn chỉ đang áp dụng lời khuyên của bạn về "luôn luôn trích dẫn trừ khi bạn có lý do chính đáng để không"? : p
rahmu

1
@rahmu Các trích dẫn là cần thiết để tránh chia tách và tập trung vào các yếu tố riêng lẻ. Xem xét myarray=("hello world" wibble)(2 phần tử, phần tử đầu tiên chứa khoảng trắng): work_on_array "${myarray[@]}"truyền 2 tham số hello worldwibble; work_on_array ${myarray[@]}vượt qua 2 tham số hello, worldwibble. Và với myarray=(*), work_on_array ${myarray[@]}vượt qua danh sách các tập tin trong thư mục hiện tại. (Do đó, đây là một trong nhiều trường hợp mà lời khuyên của tôi tạo ra sự khác biệt thực tế.)
Gilles 'SO- ngừng trở nên xấu xa'

Sửa lỗi cho tôi nếu tôi sai, nhưng tôi tin rằng có một lỗi đánh máy trong những gì bạn đã viết: bản mở rộng không được trích dẫn vượt qua 3 thông số , không phải 2.
rahmu

1
@rahmu Có hai thông số: sợ hãi và bất ngờ và hiệu quả tàn nhẫn. (Nói cách khác, bạn nói đúng, có một typo: hello, worldwibblelàm cho 3 thông số.)
Gilles 'Somali dừng vốn là xấu'

4

Có một cách trong bash 4.3+, có lẽ đến từ 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

Xem thêm declare -n.


Hừ, thú vị. Vâng, điều này đến từ ksh, và hoạt động trong mksh không thay đổi.
mirabilos

1

Phụ thuộc vào các phiên bản AT & T ksh93 và mksh gần đây của Korn Shell hỗ trợ điều này:

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

    echo "${arr[idx]}"
}

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

Trong trình bao hiện tại của tôi, điều này không xuất ra BẠC.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.