Truyền mảng như tham số trong bash


188

Làm thế nào tôi có thể truyền một mảng làm tham số cho hàm bash?

Lưu ý: Sau khi không tìm thấy câu trả lời ở đây trên Stack Overflow, tôi đã tự mình đăng giải pháp hơi thô thiển của mình. Nó chỉ cho phép một mảng được truyền và nó là phần tử cuối cùng của danh sách tham số. Trên thực tế, nó hoàn toàn không vượt qua mảng, mà là một danh sách các phần tử của nó, được tập hợp lại thành một mảng bằng cách gọi là_feft (), nhưng nó hoạt động với tôi. Nếu ai đó biết một cách tốt hơn, hãy thêm nó ở đây.


1
Ở đây bạn có tài liệu tham khảo tốt đẹp và tấn ví dụ.
Artem Barger

16
Errr ... Ba câu hỏi về một câu hỏi năm tuổi trong cùng một phút?
DevSolar

Câu trả lời:


219

Bạn có thể truyền nhiều mảng dưới dạng đối số bằng cách sử dụng một cái gì đó như thế này:

takes_ary_as_arg()
{
    declare -a argAry1=("${!1}")
    echo "${argAry1[@]}"

    declare -a argAry2=("${!2}")
    echo "${argAry2[@]}"
}
try_with_local_arys()
{
    # array variables could have local scope
    local descTable=(
        "sli4-iread"
        "sli4-iwrite"
        "sli3-iread"
        "sli3-iwrite"
    )
    local optsTable=(
        "--msix  --iread"
        "--msix  --iwrite"
        "--msi   --iread"
        "--msi   --iwrite"
    )
    takes_ary_as_arg descTable[@] optsTable[@]
}
try_with_local_arys

sẽ lặp lại:

sli4-iread sli4-iwrite sli3-iread sli3-iwrite  
--msix  --iread --msix  --iwrite --msi   --iread --msi   --iwrite

Chỉnh sửa / ghi chú: (từ bình luận bên dưới)

  • descTableoptsTableđược truyền dưới dạng tên và được mở rộng trong hàm. Do đó, không $cần thiết khi được đưa ra làm tham số.
  • Lưu ý rằng điều này vẫn hoạt động ngay cả với descTablevv được xác định local, bởi vì người dân địa phương có thể nhìn thấy các chức năng mà họ gọi.
  • Các !trong ${!1}mở rộng biến arg 1.
  • declare -a chỉ làm cho mảng được lập chỉ mục rõ ràng, nó không thực sự cần thiết.

14
Một điều cần lưu ý là nếu mảng ban đầu thưa thớt, thì mảng trong hàm nhận sẽ không có cùng chỉ số.
Tạm dừng cho đến khi có thông báo mới.

13
Điều này thật tuyệt vời, nhưng Ken hoặc ai đó có thể giải thích một vài điều khiến tôi thắc mắc về lý do tại sao nó hoạt động: 1 - Tôi đã nghĩ rằng descTable và optsTable sẽ phải được thêm tiền tố khi được chuyển qua làm đối số hàm. 2 - Trong dòng đầu tiên của "mất ...", tại sao cần phải khai báo mảng rõ ràng? 3 - Và những gì làm! nghĩa là trong biểu thức $ {! 1} và tại sao [@] không bắt buộc hoặc thậm chí không được phép ở đó? - Điều này hoạt động, và tất cả các chi tiết này dường như là cần thiết dựa trên thử nghiệm của tôi, nhưng tôi muốn hiểu tại sao!
Jan Hettich

8
1: descTable và optsTable chỉ được truyền dưới dạng tên, do đó không có $, chúng sẽ chỉ được mở rộng trong hàm được gọi là 2: không hoàn toàn chắc chắn, nhưng tôi nghĩ rằng nó không thực sự cần thiết 3: the! được sử dụng vì các tham số được truyền cho hàm cần được mở rộng hai lần: $ 1 mở rộng thành "descTable [@]" và điều đó nên được mở rộng thành "$ {descTable [@]}". Cú pháp $ {! 1} thực hiện điều này.
Elmar Zander

8
Tôi không nghĩ phần "tuyên bố -a" là cần thiết. Sự tồn tại của dấu ngoặc đơn đã xác định LHS của phép gán là một mảng.
Erik Aronesty

3
Câu trả lời này đã giúp tôi giải quyết một vấn đề ngay bây giờ. Tuy nhiên, tôi muốn chỉ ra rằng trên máy của mình (sử dụng bash 4.3.42), "$ {! 1}" và "$ {! 2}" cần phải xóa dấu ngoặc kép. Nếu bạn không làm như vậy, giá trị của mảng ban đầu được đọc dưới dạng một chuỗi và được gán cho argAry1 [0] và argAry2 [0], về cơ bản có nghĩa là cấu trúc mảng bị mất.
user.friendly

85

Lưu ý: Đây là giải pháp hơi thô mà tôi tự đăng, sau khi không tìm thấy câu trả lời ở đây trên Stack Overflow. Nó chỉ cho phép một mảng được truyền và nó là phần tử cuối cùng của danh sách tham số. Trên thực tế, nó hoàn toàn không vượt qua mảng, mà là một danh sách các phần tử của nó, được tập hợp lại thành một mảng bằng cách gọi là_feft (), nhưng nó hoạt động với tôi. Một lúc nào đó Ken đã đăng giải pháp của mình, nhưng tôi giữ tôi ở đây để tham khảo "lịch sử".

calling_function()
{
    variable="a"
    array=( "x", "y", "z" )
    called_function "${variable}" "${array[@]}"
}

called_function()
{
    local_variable="${1}"
    shift
    local_array=("${@}")
}

Được cải thiện bởi TheBotto, cảm ơn.


19
Ba năm sau thực tế, câu trả lời này - chỉ được giữ lại vì lý do lịch sử - đã nhận được hai lượt tải xuống trong vòng một vài ngày. Như thường lệ trên SO, không có bất kỳ lưu ý nào về lý do tại sao mọi người nghĩ rằng điều này được bảo hành. Lưu ý rằng câu trả lời này có trước tất cả những câu hỏi khác và tôi đã chấp nhận câu trả lời của Ken là giải pháp tốt nhất. Tôi hoàn toàn biết rằng nó không ở đâu gần hoàn hảo, nhưng trong bốn tháng, nó là thứ tốt nhất có sẵn trên SO. Tại sao nó nên bị hạ bệ hai năm sau khi nó chiếm vị trí thứ hai với giải pháp hoàn hảo của Ken nằm ngoài tôi.
DevSolar

@geirha: Tôi sẽ yêu cầu bạn kiểm tra xem ai đã đăng câu hỏi, ai đã đăng câu trả lời này và ai có thể chấp nhận câu trả lời mà bạn đang gọi là "xấu". ;-) Bạn cũng có thể muốn kiểm tra Ghi chú trong câu hỏi, điều này chỉ ra lý do tại sao giải pháp này kém hơn Ken.
DevSolar

2
Tôi biết bạn đã hỏi câu hỏi, bạn đã viết câu trả lời này, và rằng bạn đã chấp nhận câu trả lời tồi. Đó là lý do tại sao tôi nói nó theo cách đó. Lý do câu trả lời được chấp nhận là xấu là vì nó đang cố gắng vượt qua mảng bằng cách tham chiếu, đó là điều bạn thực sự nên tránh. Ngoài ra, ví dụ trộn nhiều đối số thành một chuỗi. Nếu bạn thực sự cần phải vượt qua các mảng bằng cách tham chiếu, bash là ngôn ngữ sai để bắt đầu. Ngay cả với các biến nameref mới của bash 4.3, bạn không thể tránh va chạm tên (tham chiếu vòng tròn) một cách an toàn.
geirha

4
Chà, bạn có thể vượt qua nhiều mảng nếu bạn bao gồm số lượng phần tử của mỗi mảng. called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"v.v ... vẫn còn một số hạn chế rõ ràng, nhưng thực sự, tốt hơn là giải quyết vấn đề theo cách ngôn ngữ hỗ trợ, thay vì cố gắng uốn cong ngôn ngữ để làm việc theo cách bạn quen với các ngôn ngữ khác.
geirha

1
@geirha: Chà, tôi đoán chúng ta sẽ phải đồng ý rằng chúng tôi không đồng ý, và bạn sẽ phải để tôi trở thành thẩm phán trả lời câu hỏi của tôi tốt nhất. Cá nhân, tôi rất thích chuyển các mảng bằng cách tham chiếu dù thế nào (bất kể ngôn ngữ, để lưu bản sao dữ liệu); thậm chí còn hơn thế khi giải pháp thay thế là cúi xuống về phía sau và vượt qua kích thước mảng dưới dạng tham số bổ sung ...
DevSolar

38

Nhận xét về giải pháp Ken Bertelson và trả lời Jan Hettich:

Làm thế nào nó hoạt động

các takes_ary_as_arg descTable[@] optsTable[@]dòng trong try_with_local_arys()chức năng gửi:

  1. Điều này thực sự tạo ra một bản sao của các mảng descTableoptsTablecác hàm có thể truy cập được takes_ary_as_arg.
  2. takes_ary_as_arg()Hàm nhận descTable[@]optsTable[@]dưới dạng chuỗi, có nghĩa là $1 == descTable[@]$2 == optsTable[@].
  3. khi bắt đầu takes_ary_as_arg()hàm, nó sử dụng ${!parameter}cú pháp, được gọi là tham chiếu gián tiếp hoặc đôi khi được tham chiếu kép , điều này có nghĩa là thay vì sử dụng $1giá trị của ', chúng tôi sử dụng giá trị của giá trị mở rộng của$1 , ví dụ:

    baba=booba
    variable=baba
    echo ${variable} # baba
    echo ${!variable} # booba

    tương tự như vậy cho $2.

  4. đưa cái này vào argAry1=("${!1}")tạo ra argAry1như một mảng (dấu ngoặc sau =) với phần mở rộng descTable[@], giống như viết argAry1=("${descTable[@]}")trực tiếp ở đó . những declarecó được không cần thiết.

Lưu ý: Điều đáng nói là việc khởi tạo mảng bằng biểu mẫu khung này sẽ khởi tạo mảng mới theo IFShoặc Dấu tách trường nội bộ theo tab mặc định , dòng mới và dấu cách . trong trường hợp đó, vì nó sử dụng [@]ký hiệu, mỗi phần tử được nhìn thấy như thể nó được trích dẫn (trái với [*]).

Đặt phòng của tôi với nó

Trong BASH, phạm vi biến cục bộ là hàm hiện tại và mọi hàm con được gọi từ nó, điều này có nghĩa là takes_ary_as_arg()hàm "nhìn thấy" các mảng descTable[@]optsTable[@]mảng, do đó nó đang hoạt động (xem phần giải thích ở trên).

Trong trường hợp đó, tại sao không trực tiếp nhìn vào các biến đó? Nó giống như viết ở đó:

argAry1=("${descTable[@]}")

Xem giải thích ở trên, chỉ sao chép descTable[@]các giá trị của mảng theo hiện tại IFS.

Tóm tắt

Điều này là vượt qua, về bản chất, không có gì bằng giá trị - như thường lệ.

Tôi cũng muốn nhấn mạnh nhận xét của Dennis Williamson ở trên: mảng thưa thớt (mảng không có tất cả các khóa được xác định - với "lỗ" trong chúng) sẽ không hoạt động như mong đợi - chúng tôi sẽ làm mất các phím và "ngưng tụ" mảng.

Điều đó đang được nói, tôi thấy giá trị cho tổng quát hóa, do đó các hàm có thể nhận được các mảng (hoặc bản sao) mà không cần biết tên:

  • cho ~ "bản sao": kỹ thuật này là đủ tốt, chỉ cần lưu ý rằng các chỉ số (phím) đã biến mất.
  • đối với các bản sao thực: chúng ta có thể sử dụng một eval cho các khóa, ví dụ:

    eval local keys=(\${!$1})

và sau đó một vòng lặp sử dụng chúng để tạo một bản sao. Lưu ý: ở đây !không được sử dụng để đánh giá gián tiếp / kép trước đó, mà là trong bối cảnh mảng, nó trả về các chỉ số mảng (khóa).

  • và, tất nhiên, nếu chúng ta vượt qua descTableoptsTablechuỗi (không có [@]), chúng ta có thể sử dụng chính mảng đó (như trong tham chiếu) với eval. cho một hàm chung chấp nhận mảng.

2
Giải thích tốt về cơ chế đằng sau lời giải thích của Ken Bertelson. Đối với câu hỏi "Trong trường hợp đó, tại sao không trực tiếp nhìn vào các biến đó?", Tôi sẽ trả lời: chỉ đơn giản là để sử dụng lại hàm. Giả sử tôi cần gọi một hàm với Array1, sau đó Array2, việc chuyển các tên mảng trở nên tiện dụng.
gfrigon

Câu trả lời tuyệt vời, chúng tôi cần giải thích nhiều hơn như thế này!
Édouard Lopez

21

Vấn đề cơ bản ở đây là (các) nhà phát triển bash đã thiết kế / triển khai các mảng thực sự làm hỏng pooch. Họ quyết định rằng đó ${array}chỉ là một bàn tay ngắn ${array[0]}, đó là một sai lầm tồi tệ. Đặc biệt là khi bạn xem xét điều đó ${array[0]}không có ý nghĩa và đánh giá chuỗi trống nếu kiểu mảng là kết hợp.

Việc gán một mảng có dạng array=(value1 ... valueN)trong đó giá trị có cú pháp [subscript]=string, do đó gán giá trị trực tiếp cho một chỉ mục cụ thể trong mảng. Điều này làm cho nó có thể có hai loại mảng, được lập chỉ mục số và băm được lập chỉ mục (được gọi là mảng kết hợp theo cách nói bash). Nó cũng làm cho nó để bạn có thể tạo các mảng được lập chỉ mục số thưa thớt. Rời khỏi [subscript]=phần này là bàn tay ngắn cho một mảng được lập chỉ mục bằng số, bắt đầu với chỉ số thứ tự là 0 và tăng dần với mỗi giá trị mới trong câu lệnh gán.

Do đó, ${array}nên đánh giá toàn bộ mảng, chỉ mục và tất cả. Nó nên đánh giá ngược lại với câu lệnh gán. Bất kỳ CS năm thứ ba chính cũng nên biết điều đó. Trong trường hợp đó, mã này sẽ hoạt động chính xác như bạn mong đợi:

declare -A foo bar
foo=${bar}

Sau đó, việc truyền các mảng theo giá trị cho các hàm và gán một mảng cho một mảng khác sẽ hoạt động khi phần còn lại của cú pháp shell ra lệnh. Nhưng vì họ đã không làm điều này đúng, toán tử gán =không hoạt động cho các mảng và các mảng không thể được truyền theo giá trị cho các hàm hoặc cho các chuỗi con hoặc đầu ra nói chung ( echo ${array}) mà không có mã để nhai hết tất cả.

Vì vậy, nếu nó đã được thực hiện đúng, thì ví dụ sau đây sẽ cho thấy mức độ hữu ích của mảng trong bash có thể tốt hơn đáng kể:

simple=(first=one second=2 third=3)
echo ${simple}

đầu ra kết quả phải là:

(first=one second=2 third=3)

Sau đó, các mảng có thể sử dụng toán tử gán và được truyền theo giá trị cho các hàm và thậm chí các tập lệnh shell khác. Dễ dàng lưu trữ bằng cách xuất ra một tệp và dễ dàng tải từ tệp vào tập lệnh.

declare -A foo
read foo <file

Than ôi, chúng tôi đã bị thất vọng bởi một nhóm phát triển bash siêu hạng khác.

Như vậy, để truyền một mảng cho một hàm, thực sự chỉ có một tùy chọn và đó là sử dụng tính năng nameref:

function funky() {
    local -n ARR

    ARR=$1
    echo "indexes: ${!ARR[@]}"
    echo "values: ${ARR[@]}"
}

declare -A HASH

HASH=([foo]=bar [zoom]=fast)
funky HASH # notice that I'm just passing the word 'HASH' to the function

sẽ dẫn đến kết quả đầu ra sau đây:

indexes: foo zoom
values: bar fast

Vì điều này được truyền bằng tham chiếu, bạn cũng có thể gán cho mảng trong hàm. Đúng, mảng được tham chiếu phải có phạm vi toàn cầu, nhưng đó không phải là vấn đề quá lớn, vì đây là kịch bản shell. Để truyền một mảng được lập chỉ mục liên kết hoặc thưa thớt theo giá trị cho một hàm đòi hỏi phải ném tất cả các chỉ mục và các giá trị vào danh sách đối số (không quá hữu ích nếu đó là một mảng lớn) như các chuỗi đơn như thế này:

funky "${!array[*]}" "${array[*]}"

và sau đó viết một loạt mã bên trong hàm để tập hợp lại mảng.


1
Giải pháp sử dụng local -nlà tốt hơn và cập nhật hơn so với câu trả lời được chấp nhận. Giải pháp này cũng sẽ làm việc cho một biến của bất kỳ loại nào. Ví dụ được liệt kê trong câu trả lời này có thể được rút ngắn thành local -n ARR=${1}. Tuy nhiên, -ntùy chọn cho local/ declarechỉ khả dụng trong Bash phiên bản 4.3 trở lên.
richardjsimkins 14/03/2016

Cái này đẹp đấy! Gotcha nhỏ: nếu bạn truyền một biến có cùng tên với đối số cục bộ của hàm (vd funky ARR), shell sẽ đưa ra cảnh báo circular name reference, vì về cơ bản, hàm sẽ cố gắng thực hiện local -n ARR=ARR. Thảo luận tốt về chủ đề này.
Gene Pavlovsky

5

Câu trả lời của DevSolar có một điểm tôi không hiểu (có thể anh ta có lý do cụ thể để làm như vậy, nhưng tôi không thể nghĩ ra): Anh ta đặt mảng từ phần tử tham số vị trí theo yếu tố, lặp.

Một approuch dễ dàng hơn sẽ là

called_function()
{
  ...
  # do everything like shown by DevSolar
  ...

  # now get a copy of the positional parameters
  local_array=("$@")
  ...
}

1
Lý do của tôi không làm như vậy là tôi đã không đùa giỡn với các mảng bash cho đến vài ngày trước. Trước đây tôi đã chuyển sang Perl nếu nó trở nên phức tạp, một lựa chọn tôi không có trong công việc hiện tại. Cảm ơn các gợi ý!
DevSolar

3
function aecho {
  set "$1[$2]"
  echo "${!1}"
}

Thí dụ

$ foo=(dog cat bird)

$ aecho foo 1
cat

3

Một cách dễ dàng để vượt qua một số mảng làm tham số là sử dụng chuỗi phân tách ký tự. Bạn có thể gọi kịch bản của bạn như thế này:

./myScript.sh "value1;value2;value3" "somethingElse" "value4;value5" "anotherOne"

Sau đó, bạn có thể trích xuất nó trong mã của bạn như thế này:

myArray=$1
IFS=';' read -a myArray <<< "$myArray"

myOtherArray=$3
IFS=';' read -a myOtherArray <<< "$myOtherArray"

Theo cách này, bạn thực sự có thể truyền nhiều mảng dưới dạng tham số và nó không phải là tham số cuối cùng.


1

Cái này hoạt động ngay cả với không gian:

format="\t%2s - %s\n"

function doAction
{
  local_array=("$@")
  for (( i = 0 ; i < ${#local_array[@]} ; i++ ))
    do
      printf "${format}" $i "${local_array[$i]}"
  done
  echo -n "Choose: "
  option=""
  read -n1 option
  echo ${local_array[option]}
  return
}

#the call:
doAction "${tools[@]}"

2
Tôi tự hỏi những gì là điểm ở đây. Đây chỉ là tranh luận bình thường đi qua. Cú pháp "$ @" được tạo để hoạt động cho các khoảng trắng: "$ @" tương đương với "$ 1" "$ 2" ...
Andreas Spindler

Tôi có thể truyền 2 mảng cho một hàm không?
pieaveragy

1

Với một vài thủ thuật, bạn thực sự có thể chuyển các tham số được đặt tên cho các hàm, cùng với các mảng.

Phương thức tôi đã phát triển cho phép bạn truy cập các tham số được truyền vào một hàm như thế này:

testPassingParams() {

    @var hello
    l=4 @array anArrayWithFourElements
    l=2 @array anotherArrayWithTwo
    @var anotherSingle
    @reference table   # references only work in bash >=4.3
    @params anArrayOfVariedSize

    test "$hello" = "$1" && echo correct
    #
    test "${anArrayWithFourElements[0]}" = "$2" && echo correct
    test "${anArrayWithFourElements[1]}" = "$3" && echo correct
    test "${anArrayWithFourElements[2]}" = "$4" && echo correct
    # etc...
    #
    test "${anotherArrayWithTwo[0]}" = "$6" && echo correct
    test "${anotherArrayWithTwo[1]}" = "$7" && echo correct
    #
    test "$anotherSingle" = "$8" && echo correct
    #
    test "${table[test]}" = "works"
    table[inside]="adding a new value"
    #
    # I'm using * just in this example:
    test "${anArrayOfVariedSize[*]}" = "${*:10}" && echo correct
}

fourElements=( a1 a2 "a3 with spaces" a4 )
twoElements=( b1 b2 )
declare -A assocArray
assocArray[test]="works"

testPassingParams "first" "${fourElements[@]}" "${twoElements[@]}" "single with spaces" assocArray "and more... " "even more..."

test "${assocArray[inside]}" = "adding a new value"

Nói cách khác, không chỉ bạn có thể gọi các tham số của mình bằng tên của chúng (mà tạo ra lõi dễ đọc hơn), bạn thực sự có thể truyền các mảng (và tham chiếu đến các biến - mặc dù tính năng này chỉ hoạt động trong bash 4.3)! Thêm vào đó, các biến được ánh xạ đều nằm trong phạm vi cục bộ, chỉ là $ 1 (và các biến khác).

Mã làm cho công việc này khá nhẹ và hoạt động cả trong bash 3 và bash 4 (đây là những phiên bản duy nhất tôi đã thử nghiệm với nó). Nếu bạn quan tâm đến nhiều thủ thuật như thế này giúp phát triển với bash đẹp hơn và dễ dàng hơn, bạn có thể xem Bash Infinity Framework của tôi , mã dưới đây được phát triển cho mục đích đó.

Function.AssignParamLocally() {
    local commandWithArgs=( $1 )
    local command="${commandWithArgs[0]}"

    shift

    if [[ "$command" == "trap" || "$command" == "l="* || "$command" == "_type="* ]]
    then
        paramNo+=-1
        return 0
    fi

    if [[ "$command" != "local" ]]
    then
        assignNormalCodeStarted=true
    fi

    local varDeclaration="${commandWithArgs[1]}"
    if [[ $varDeclaration == '-n' ]]
    then
        varDeclaration="${commandWithArgs[2]}"
    fi
    local varName="${varDeclaration%%=*}"

    # var value is only important if making an object later on from it
    local varValue="${varDeclaration#*=}"

    if [[ ! -z $assignVarType ]]
    then
        local previousParamNo=$(expr $paramNo - 1)

        if [[ "$assignVarType" == "array" ]]
        then
            # passing array:
            execute="$assignVarName=( \"\${@:$previousParamNo:$assignArrLength}\" )"
            eval "$execute"
            paramNo+=$(expr $assignArrLength - 1)

            unset assignArrLength
        elif [[ "$assignVarType" == "params" ]]
        then
            execute="$assignVarName=( \"\${@:$previousParamNo}\" )"
            eval "$execute"
        elif [[ "$assignVarType" == "reference" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        elif [[ ! -z "${!previousParamNo}" ]]
        then
            execute="$assignVarName=\"\$$previousParamNo\""
            eval "$execute"
        fi
    fi

    assignVarType="$__capture_type"
    assignVarName="$varName"
    assignArrLength="$__capture_arrLength"
}

Function.CaptureParams() {
    __capture_type="$_type"
    __capture_arrLength="$l"
}

alias @trapAssign='Function.CaptureParams; trap "declare -i \"paramNo+=1\"; Function.AssignParamLocally \"\$BASH_COMMAND\" \"\$@\"; [[ \$assignNormalCodeStarted = true ]] && trap - DEBUG && unset assignVarType && unset assignVarName && unset assignNormalCodeStarted && unset paramNo" DEBUG; '
alias @param='@trapAssign local'
alias @reference='_type=reference @trapAssign local -n'
alias @var='_type=var @param'
alias @params='_type=params @param'
alias @array='_type=array @param'

1

Chỉ cần thêm vào câu trả lời được chấp nhận, vì tôi thấy nó không hoạt động tốt nếu nội dung mảng đôi khi như:

RUN_COMMANDS=(
  "command1 param1... paramN"
  "command2 param1... paramN"
)

Trong trường hợp này, mỗi thành viên của mảng được phân chia, do đó, mảng mà hàm nhìn thấy tương đương với:

RUN_COMMANDS=(
    "command1"
    "param1"
     ...
    "command2"
    ...
)

Để làm cho trường hợp này hoạt động, cách tôi tìm thấy là chuyển tên biến cho hàm, sau đó sử dụng eval:

function () {
    eval 'COMMANDS=( "${'"$1"'[@]}" )'
    for COMMAND in "${COMMANDS[@]}"; do
        echo $COMMAND
    done
}

function RUN_COMMANDS

Chỉ cần 2 © của tôi


1

Xấu xí như vậy, đây là một cách giải quyết hoạt động miễn là bạn không truyền một mảng rõ ràng, nhưng một biến tương ứng với một mảng:

function passarray()
{
    eval array_internally=("$(echo '${'$1'[@]}')")
    # access array now via array_internally
    echo "${array_internally[@]}"
    #...
}

array=(0 1 2 3 4 5)
passarray array # echo's (0 1 2 3 4 5) as expected

Tôi chắc chắn rằng ai đó có thể đưa ra một triển khai ý tưởng rõ ràng, nhưng tôi thấy đây là một giải pháp tốt hơn là truyền một mảng "{array[@]"}và sau đó truy cập nó bằng cách sử dụng nội bộ array_inside=("$@"). Điều này trở nên phức tạp khi có các vị trí / getoptstham số khác. Trong những trường hợp này, trước tiên tôi phải xác định và sau đó loại bỏ các tham số không liên quan đến mảng bằng cách sử dụng một số kết hợp shiftvà loại bỏ phần tử mảng.

Một quan điểm thuần túy có khả năng xem cách tiếp cận này là vi phạm ngôn ngữ, nhưng thực tế mà nói, cách tiếp cận này đã giúp tôi tiết kiệm rất nhiều đau buồn. Trong một chủ đề liên quan, tôi cũng sử dụng evalđể gán một mảng được xây dựng bên trong cho một biến có tên theo tham số target_varnametôi truyền cho hàm:

eval $target_varname=$"(${array_inside[@]})"

Hy vọng điều này sẽ giúp được ai đó.


0

Yêu cầu : Hàm tìm chuỗi trong một mảng.
Đây là một sự đơn giản hóa nhỏ của giải pháp DevSolar ở chỗ nó sử dụng các đối số được truyền thay vì sao chép chúng.

myarray=('foobar' 'foxbat')

function isInArray() {
  local item=$1
  shift
  for one in $@; do
    if [ $one = $item ]; then
      return 0   # found
    fi
  done
  return 1       # not found
}

var='foobar'
if isInArray $var ${myarray[@]}; then
  echo "$var found in array"
else
  echo "$var not found in array"
fi 

0

Câu trả lời ngắn gọn của tôi là:

function display_two_array {
    local arr1=$1
    local arr2=$2
    for i in $arr1
    do
       "arrary1: $i"
    done
    
    for i in $arr2
    do
       "arrary2: $i"
    done
}

test_array=(1 2 3 4 5)
test_array2=(7 8 9 10 11)

display_two_array "${test_array[*]}" "${test_array2[*]}"
Cần lưu ý rằng ${test_array[*]}${test_array2[*]}nên được bao quanh bởi "", nếu không bạn sẽ thất bại.


Ví dụ của bạn không chính xác vì nó không đầy đủ. Vui lòng cung cấp mã đầy đủ của tập lệnh.
Dennis VR
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.