Jak mogę przekazać tablicę jako parametr do funkcji bash?
Uwaga: po tym, jak nie znalazłem tutaj odpowiedzi na temat Przepełnienia stosu, sam opublikowałem swoje nieco prymitywne rozwiązanie. Pozwala to na przekazanie tylko jednej tablicy i jest to ostatni element listy parametrów. Właściwie to wcale nie przekazuje tablicy, ale listę jej elementów, które są ponownie składane w tablicę przez wywołanie funkcji_funkcji (), ale działało to dla mnie. Jeśli ktoś zna lepszy sposób, dodaj go tutaj.
Odpowiedzi:
Jako argumenty możesz przekazać wiele tablic, używając czegoś takiego:
wyemituje echo:
Edytuj / notatki: (z komentarzy poniżej)
descTable
ioptsTable
są przekazywane jako nazwy i są rozwijane w funkcji. Dlatego nie$
jest potrzebny, gdy podano go jako parametry.descTable
zdefiniowaniu etclocal
, ponieważ locals są widoczne dla wywoływanych funkcji.!
W${!1}
rozszerza zmiennej arg 1.declare -a
sprawia, że indeksowana tablica jest jawna, nie jest to absolutnie konieczne.źródło
Uwaga: jest to dość prymitywne rozwiązanie, które sam opublikowałem, po tym, jak nie znalazłem tutaj odpowiedzi na Przepełnienie stosu. Pozwala to na przekazanie tylko jednej tablicy i jest to ostatni element listy parametrów. Właściwie to wcale nie przekazuje tablicy, ale listę jej elementów, które są ponownie składane w tablicę przez wywołanie funkcji_funkcji (), ale działało to dla mnie. Nieco później Ken opublikował swoje rozwiązanie, ale zatrzymałem je tutaj w celu odniesienia do „historii”.
Ulepszony przez TheBonsai, dzięki.
źródło
called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"
itd. ... nadal z pewnymi oczywistymi ograniczeniami, ale naprawdę lepiej jest rozwiązać problem w sposób obsługiwany przez język, niż próbować nakłonić go do działania w sposób, w jaki jesteś przyzwyczajony w innych językach.Komentując rozwiązanie Kena Bertelsona i odpowiadając na Jana Hetticha:
Jak to działa
takes_ary_as_arg descTable[@] optsTable[@]
linii wtry_with_local_arys()
funkcji wysyła:descTable
i,optsTable
które są dostępne dlatakes_ary_as_arg
funkcji.takes_ary_as_arg()
funkcja przyjmujedescTable[@]
ioptsTable[@]
jako ciągi znaków, co oznacza$1 == descTable[@]
i$2 == optsTable[@]
.na początku
takes_ary_as_arg()
funkcji używa${!parameter}
składni, która nazywa się referencją pośrednią lub czasami podwójną , co oznacza, że zamiast używać$1
wartości, używamy wartości rozszerzonej wartości$1
, na przykład:podobnie dla
$2
.argAry1=("${!1}")
tworzyargAry1
jako tablicę (nawiasy poniżej=
) z rozwiniętymdescTable[@]
, tak jak pisanieargAry1=("${descTable[@]}")
bezpośrednio tam .declare
nie jest wymagane.Uwaga: Warto wspomnieć, że inicjalizacji tablicy za pomocą tego formularza wspornik inicjuje nową tablicę według
IFS
lub polowego Wewnętrznego Separator , który jest domyślnie zakładki , znak nowej linii i przestrzeni . w takim przypadku, ponieważ używał[@]
notacji, każdy element jest postrzegany sam, jakby był cytowany (w przeciwieństwie do[*]
).Moja rezerwacja z tym
W
BASH
, zakres zmiennej lokalnej jest funkcją bieżącą i każda wywoływana z niej funkcja potomna przekłada się na fakt, żetakes_ary_as_arg()
funkcja „widzi” jedescTable[@]
ioptsTable[@]
tablice, a zatem działa (patrz powyższe wyjaśnienie).W takim razie dlaczego nie spojrzeć bezpośrednio na te zmienne? To jest jak pisanie tam:
Zobacz powyższe objaśnienie, które po prostu kopiuje
descTable[@]
wartości tablicy zgodnie z bieżącymIFS
.W podsumowaniu
Chciałbym również podkreślić powyższy komentarz Dennisa Williamsona: rzadkie tablice (tablice bez wszystkich definicji klawiszy - z „dziurami” w nich) nie będą działać zgodnie z oczekiwaniami - stracilibyśmy klucze i „kondensowali” tablicę.
Biorąc to pod uwagę, widzę wartość dla uogólnienia, funkcje mogą więc uzyskać tablice (lub kopie) bez znajomości nazw:
dla prawdziwych kopii: możemy użyć eval dla kluczy, na przykład:
a następnie pętlę używającą ich do utworzenia kopii. Uwaga: tutaj
!
nie jest używana, to poprzednia pośrednia / podwójna ocena, ale raczej w kontekście tablicowym zwraca indeksy tablic (klucze).descTable
ioptsTable
napisy (bez[@]
), moglibyśmy użyć samej tablicy (jak w referencji) zeval
. dla ogólnej funkcji, która akceptuje tablice.źródło
Array1
, a następnie za pomocąArray2
, przekazywanie nazw tablic staje się przydatne.Podstawowym problemem jest to, że twórcy bashów, którzy zaprojektowali / zaimplementowali tablice, naprawdę spieprzyli puchata. Uznali, że
${array}
to krótka ręka${array[0]}
, co było poważnym błędem. Zwłaszcza, jeśli weźmiesz pod uwagę, że${array[0]}
nie ma to znaczenia i zwraca pusty ciąg, jeśli typ tablicy jest asocjacyjny.Przypisanie tablicy ma postać, w
array=(value1 ... valueN)
której wartość ma składnię[subscript]=string
, tym samym przypisując wartość bezpośrednio do określonego indeksu w tablicy. To sprawia, że mogą istnieć dwa typy tablic, indeksowane numerycznie i indeksowane hash (zwane tablicami asocjacyjnymi w języku bash). Dzięki temu możesz tworzyć rzadkie tablice indeksowane numerycznie. Wyjście z tej[subscript]=
części jest krótką ręką dla tablicy indeksowanej numerycznie, zaczynając od porządkowego indeksu 0 i zwiększając każdą nową wartość w instrukcji przypisania.Dlatego
${array}
powinien oceniać całą tablicę, indeksy i wszystkie. Powinien być odwrócony do instrukcji przypisania. Każdy student CS-dur trzeciego roku powinien o tym wiedzieć. W takim przypadku ten kod działałby dokładnie tak, jak można się spodziewać:Następnie przekazywanie tablic według wartości do funkcji i przypisywanie jednej tablicy do drugiej działałoby tak, jak dyktuje reszta składni powłoki. Ale ponieważ nie zrobili tego dobrze, operator przypisania
=
nie działa dla tablic, a tablic nie można przekazywać wartościami do funkcji lub do podpowłok lub generalnie danych wyjściowych (echo ${array}
) bez kodu, który przejrzałby to wszystko.Tak więc, jeśli zrobiono to dobrze, następujący przykład pokazałby, jak użyteczność tablic w bashu może być znacznie lepsza:
wynikowy wynik powinien wynosić:
Następnie tablice mogłyby korzystać z operatora przypisania i być przekazywane przez wartość do funkcji, a nawet innych skryptów powłoki. Łatwo przechowywane przez wyjście do pliku i łatwe ładowanie z pliku do skryptu.
Niestety, zawiódł nas świetny zespół programistów bash.
W związku z tym, aby przekazać tablicę do funkcji, jest tak naprawdę tylko jedna opcja, a mianowicie użycie funkcji nameref:
spowoduje następujące dane wyjściowe:
Ponieważ jest to przekazywane przez odwołanie, można również przypisać tablicę w funkcji. Tak, przywoływana tablica musi mieć zasięg globalny, ale nie powinno to być zbyt duże, biorąc pod uwagę, że jest to skrypt skryptowy. Aby przekazać asocjacyjną lub rzadką tablicę indeksowaną przez wartość do funkcji, należy rzucić wszystkie indeksy i wartości na listę argumentów (nie jest to zbyt przydatne, jeśli jest to duża tablica) jako pojedyncze ciągi:
a następnie napisanie wiązki kodu wewnątrz funkcji w celu ponownego złożenia tablicy.
źródło
local -n
jest lepsze i bardziej aktualne niż zaakceptowana odpowiedź. To rozwiązanie będzie również działać dla zmiennej dowolnego typu. Przykład wymieniony w tej odpowiedzi można skrócićlocal -n ARR=${1}
. Jednak-n
opcjalocal
/declare
jest dostępna tylko w wersji Bash 4.3 i nowszych.funky ARR
), Shell wyświetli ostrzeżeniecircular name reference
, ponieważ w zasadzie funkcja spróbuje to zrobićlocal -n ARR=ARR
. Dobra dyskusja na ten temat.Odpowiedź DevSolar ma jeden punkt, którego nie rozumiem (może ma konkretny powód, aby to zrobić, ale nie mogę myśleć o żadnym): Ustawia tablicę z parametrów pozycyjnych element po elemencie, iteracyjną.
Byłoby łatwiejsze podejście
źródło
Przykład
źródło
Łatwym sposobem przekazania kilku tablic jako parametru jest użycie łańcucha rozdzielanego znakami. Możesz wywołać swój skrypt w następujący sposób:
Następnie możesz wyodrębnić go w kodzie w następujący sposób:
W ten sposób możesz przekazać wiele tablic jako parametry i nie muszą to być ostatnie parametry.
źródło
Ten działa nawet ze spacjami:
źródło
Za pomocą kilku sztuczek możesz przekazać nazwane parametry do funkcji wraz z tablicami.
Opracowana przeze mnie metoda umożliwia dostęp do parametrów przekazywanych do funkcji takiej jak ta:
Innymi słowy, nie tylko możesz wywoływać swoje parametry według ich nazw (co stanowi bardziej czytelny rdzeń), możesz faktycznie przekazywać tablice (i odniesienia do zmiennych - ta funkcja działa jednak tylko w bash 4.3)! Ponadto wszystkie zmapowane zmienne są w zasięgu lokalnym, podobnie jak 1 USD (i inne).
Kod, który sprawia, że ta praca jest dość lekka i działa zarówno w bash 3, jak i bash 4 (to jedyne wersje, z którymi go testowałem). Jeśli interesuje Cię więcej takich sztuczek, które sprawiają, że programowanie w bash jest znacznie przyjemniejsze i łatwiejsze, możesz rzucić okiem na mój Bash Infinity Framework , poniższy kod został opracowany w tym celu.
źródło
Aby dodać do zaakceptowanej odpowiedzi, ponieważ znalazłem, że nie działa dobrze, jeśli zawartość tablicy jest coś takiego:
W takim przypadku każdy element tablicy zostaje podzielony, więc tablica, którą widzi funkcja, jest równoważna z:
Aby uruchomić ten przypadek, znalazłem sposób, aby przekazać nazwę zmiennej do funkcji, a następnie użyć eval:
Tylko moje 2 ©
źródło
Choć jest to brzydkie, oto obejście, które działa, o ile nie przekazujesz tablicy wprost, ale zmienna odpowiadająca tablicy:
Jestem pewien, że ktoś może wymyślić bardziej przejrzystą implementację tego pomysłu, ale uważam, że jest to lepsze rozwiązanie niż przekazywanie tablicy,
"{array[@]"}
a następnie uzyskiwanie do niej dostępu wewnętrzniearray_inside=("$@")
. Staje się to skomplikowane, gdy istnieją innegetopts
parametry pozycyjne / . W takich przypadkach musiałem najpierw określić, a następnie usunąć parametry niezwiązane z tablicą, używając kombinacjishift
usuwania elementu tablicy.Perspektywa purystyczna prawdopodobnie postrzega to podejście jako pogwałcenie języka, ale pragmatycznie rzecz biorąc, to podejście uratowało mi wiele smutku. W pokrewnym temacie używam również
eval
do przypisywania wewnętrznie skonstruowanej tablicy do zmiennej o nazwie zgodnej z parametremtarget_varname
przekazywanym do funkcji:eval $target_varname=$"(${array_inside[@]})"
Mam nadzieję, że to komuś pomoże.
źródło
Wymaganie : Funkcja znajdowania ciągu w tablicy.
Jest to niewielkie uproszczenie rozwiązania DevSolar, ponieważ wykorzystuje przekazane argumenty, a nie je kopiuje.
źródło
Moja krótka odpowiedź to:
${test_array[*]}
i${test_array2[*]}
powinny być otoczone przez „”, w przeciwnym razie zawiedziesz.źródło