Konwertuj argumenty wiersza poleceń na tablicę w Bash

160

Jak przekonwertować argumenty wiersza poleceń na tablicę skryptów bash?

Chcę to wziąć:

./something.sh arg1 arg2 arg3

i przekonwertuj go na

myArray=( arg1 arg2 arg3 )

tak, żebym mógł używać myArray do dalszego wykorzystania w skrypcie.

Ten poprzedni post SO jest bliski, ale nie omawia sposobu tworzenia tablicy: Jak analizować argumenty wiersza poleceń w Bash?

Muszę przekonwertować argumenty na zwykłą tablicę skryptów bash; Zdaję sobie sprawę, że mógłbym używać innych języków (na przykład Python), ale muszę to zrobić w bash. Chyba szukam funkcji „dołącz” lub czegoś podobnego?

AKTUALIZACJA: Chciałem również zapytać, jak sprawdzić, czy nie ma argumentów i przypisać domyślną wartość tablicy, a dzięki poniższej odpowiedzi udało mi się to działa:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi
Suman
źródło

Odpowiedzi:

206

Właściwie twoje argumenty wiersza poleceń są już praktycznie jak tablica. Przynajmniej możesz traktować $@zmienną podobnie jak tablicę. To powiedziawszy, możesz przekonwertować go na rzeczywistą tablicę, taką jak ta:

myArray=( "$@" )

Jeśli chcesz tylko wpisać argumenty i wprowadzić je do $@wartości, użyj set:

$ set -- apple banana "kiwi fruit"
$ echo "$#"
3
$ echo "$@"
apple banana kiwi fruit

Zrozumienie, jak używać struktury argumentów, jest szczególnie przydatne w POSIX sh, który nie ma nic innego jak tablica.

kojiro
źródło
2
Dzięki! Działa świetnie! Miałem właśnie zapytać, jak sprawdzić, czy nie ma żadnych argumentów i przypisać domyślną wartość tablicy, a $ # działa idealnie!
Suman
1
setpozwala ustawić parametry pozycyjne dla zakresu. Pozwala także ustawić opcje powłoki. Możesz to zrobić set foo, co będzie oznaczać $1rozszerzenie do "foo", ale jeśli twoje parametry zaczynają się od myślnika set, założysz , że chcesz ustawić opcję powłoki. Podwójny myślnik zapewnia, że ​​wszystkie poniższe parametry są interpretowane jako parametry pozycyjne do ustawienia.
kojiro
11
Jedna gotcha: echo $@wypisze wszystkie argumenty, ale echo $myArraywypisze tylko pierwszy element. Aby zobaczyć je wszystkie, użyj echo ${myArray[@]}.
z0r
4
@ z0r Jeśli nie umieścisz podwójnych cudzysłowów wokół tych rozszerzeń, bash ponownie je rozdzieli i prawdopodobnie straci znaczenie.
kojiro,
Tak, ogólny sposób na „splatowanie” tablicy i użycie każdego elementu to "${myArray[@]}". Jeśli chcesz przeglądać tablicę w pętli, potrzebujesz cudzysłowów, aby uniknąć dzielenia jej poszczególnych elementów na IFS
BallpointBen
66

Może to pomoże:

myArray=("$@") 

możesz również iterować po argumentach, pomijając „in”:

for arg; do
   echo "$arg"
done

będą równoważne

for arg in "${myArray[@]}"; do
   echo "$arg"
done
Nahuel Fouilleul
źródło
3
Pytania początkujących: skąd bash wie, co umieścić w argpolu - czy jest to predefiniowana zmienna? ${var}jest rozszerzony do treści var. ${var[n]}jest rozszerzany do zawartości elementu ntablicy var. Czy ${var[@]}następnie rozszerza całą tablicę, tj. ${var[0]} ${var[1]} ... ${var[n]}( nBędąc indeksem ostatniego elementu)?
Christian,
4
[for] bez [in] zapętli tablicę argumentów $ @ ($ 1, $ 2 itd.). Które można również ustawić za pomocą polecenia [set], na przykład set - arg1 arg2
Nahuel Fouilleul
17

Właściwie lista parametrów może być dostępna za pomocą $1 $2 ...itp.
Co jest dokładnie równoważne z:

${!i}

Tak więc listę parametrów można zmienić za pomocą set
i ${!i}jest to właściwy sposób uzyskania do nich dostępu:

$ set -- aa bb cc dd 55 ff gg hh ii jjj kkk lll
$ for ((i=0;i<=$#;i++)); do echo "$#" "$i" "${!i}"; done
12 1 aa
12 2 bb
12 3 cc
12 4 dd
12 5 55
12 6 ff
12 7 gg
12 8 hh
12 9 ii
12 10 jjj
12 11 kkk
12 12 lll

W twoim konkretnym przypadku można tego użyć (bez potrzeby stosowania tablic), aby ustawić listę argumentów, gdy żaden nie został podany:

if [ "$#" -eq 0 ]; then
    set -- defaultarg1 defaultarg2
fi

co przekłada się na to jeszcze prostsze wyrażenie:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2
Yaron
źródło
Czy przykładem echa nie powinno być: echo "$#" "$i+1" "${!i}";aby uzyskać wynik dokładnie taki, jak pokazano?
Zael
6

Oto inne użycie:

#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
   echo "${array[$i]}"
done
tuğrul altun
źródło
4

Jeszcze łatwiej, możesz działać bezpośrednio na $@;)

Oto jak przekazać listę argumentów bezpośrednio z zachęty:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go
runlevel0
źródło
1
Jeszcze łatwiej, for stuff in "$@" ; do ...to samo co for stuff ; do ...:)
kkm
1

Widok obok siebie, w jaki sposób tablica i $ @ są praktycznie takie same.

Kod:

#!/bin/bash

echo "Dollar-1 : $1"
echo "Dollar-2 : $2"
echo "Dollar-3 : $3"
echo "Dollar-AT: $@"
echo ""

myArray=( "$@" )

echo "A Val 0: ${myArray[0]}"
echo "A Val 1: ${myArray[1]}"
echo "A Val 2: ${myArray[2]}"
echo "A All Values: ${myArray[@]}"

Wejście:

./bash-array-practice.sh 1 2 3 4

Wynik:

Dollar-1 : 1
Dollar-2 : 2
Dollar-3 : 3
Dollar-AT: 1 2 3 4

A Val 0: 1
A Val 1: 2
A Val 2: 3
A All Values: 1 2 3 4
Kirin
źródło
1

Warto podkreślić znaczenie podwójnych cudzysłowów. Załóżmy, że argument zawiera spacje.

Kod:

#!/bin/bash
printf 'arguments:%s\n' "$@"
declare -a arrayGOOD=( "$@" )
declare -a arrayBAAD=(  $@  )

printf '\n%s:\n' arrayGOOD
declare -p arrayGOOD
arrayGOODlength=${#arrayGOOD[@]}
for (( i=1; i<${arrayGOODlength}+1; i++ ));
do
   echo "${arrayGOOD[$i-1]}"
done

printf '\n%s:\n' arrayBAAD
declare -p arrayBAAD
arrayBAADlength=${#arrayBAAD[@]}
for (( i=1; i<${arrayBAADlength}+1; i++ ));
do
   echo "${arrayBAAD[$i-1]}"
done

Wynik:

> ./bash-array-practice.sh 'The dog ate the "flea" -- and ' the mouse.
arguments:The dog ate the "flea" -- and 
arguments:the
arguments:mouse.

arrayGOOD:
declare -a arrayGOOD='([0]="The dog ate the \"flea\" -- and " [1]="the" [2]="mouse.")'
The dog ate the "flea" -- and 
the
mouse.

arrayBAAD:
declare -a arrayBAAD='([0]="The" [1]="dog" [2]="ate" [3]="the" [4]="\"flea\"" [5]="--" [6]="and" [7]="the" [8]="mouse.")'
The
dog
ate
the
"flea"
--
and
the
mouse.
> 
Jacob Wegelin
źródło