Конвертировать аргументы командной строки в массив в Bash

162

Как преобразовать аргументы командной строки в массив скриптов bash?

Я хочу взять это:

./something.sh arg1 arg2 arg3

и преобразовать его в

myArray=( arg1 arg2 arg3 )

так что я могу использовать myArray для дальнейшего использования в сценарии.

Этот предыдущий пост SO близок, но не касается того, как создать массив: как мне проанализировать аргументы командной строки в Bash?

Мне нужно преобразовать аргументы в обычный массив скриптов bash; Я понимаю, что могу использовать другие языки (например, Python), но нужно сделать это в bash. Я думаю, я ищу функцию "добавить" или что-то подобное?

ОБНОВЛЕНИЕ: я также хотел спросить, как проверить на нулевые аргументы и назначить значение массива по умолчанию, и благодаря ответу ниже, смог заставить это работать:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi
Суман
источник

Ответы:

208

На самом деле ваши аргументы командной строки уже практически похожи на массив. По крайней мере, вы можете рассматривать $@переменную как массив. Тем не менее, вы можете преобразовать его в фактический массив, как это:

myArray=( "$@" )

Если вы просто хотите ввести некоторые аргументы и ввести их в $@значение, используйте set:

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

Понимание того, как использовать структуру аргументов, особенно полезно в POSIX sh, который не имеет ничего другого, как массив.

Кодзиро
источник
2
Спасибо! Прекрасно работает! Собирался спросить, как проверить нулевые аргументы и назначить значение массива по умолчанию, и $ # отлично подходит для этого!
Суман
1
setпозволяет установить позиционные параметры для области. Это также позволяет вам устанавливать параметры оболочки. Вы можете сделать это set foo, что будет означать $1расширение до "foo", но если ваши параметры начинаются с тире, setвы предполагаете, что вы хотите установить параметр оболочки. Двойная черта гарантирует, что все следующие параметры будут интерпретированы как позиционные параметры, которые будут установлены.
Кодзиро
12
Одна ошибка: echo $@напечатает все аргументы, но echo $myArrayнапечатает только первый элемент. Чтобы увидеть их все, используйте echo ${myArray[@]}.
z0r
4
@ z0r Если вы не ставите двойные кавычки вокруг этих расширений, то bash переразметит их и, возможно, потеряет смысл.
Кодзиро
Правильно, общий способ «восклицательный знак» массив и использовать каждый элемент "${myArray[@]}". Если вы хотите перебрать массив, вам нужны кавычки, чтобы не разбивать его отдельные элементы на IFS
BallpointBen
66

Может быть, это может помочь:

myArray=("$@") 

также вы можете перебирать аргументы, опуская 'in':

for arg; do
   echo "$arg"
done

будет эквивалентно

for arg in "${myArray[@]}"; do
   echo "$arg"
done
Науэль Фуйе
источник
3
Вопросы новичка: как bash знает, что поместить в argполе - это предопределенная переменная? ${var}расширяется до содержания var. ${var[n]}расширяется до содержимого элемента nмассива var. Является ли ${var[@]}то расширение всего массива, т.е. ${var[0]} ${var[1]} ... ${var[n]}nявляющийся индексом последнего элемента)?
Кристиан
4
[for] без [in] будет перебирать массив аргументов $ @ ($ 1, $ 2 и т. д.). Который может быть установлен также с помощью команды [set], например set - arg1 arg2
Науэль Фуйе
17

На самом деле список параметров может быть доступен с помощью $1 $2 ...и т. Д.
Что в точности эквивалентно:

${!i}

Итак, список параметров можно изменить с помощью set,
и ${!i}это правильный способ доступа к ним:

$ 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

В вашем конкретном случае это можно использовать (без необходимости использования массивов), чтобы установить список аргументов, когда ни один из них не был задан:

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

что переводит к этому еще более простому выражению:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2
Ярон
источник
Разве не должно быть эхо-примера: echo "$#" "$i+1" "${!i}";получить вывод точно так, как показано?
Заэль
6

Вот еще одно использование:

#!/bin/bash
array=( "$@" )
arraylength=${#array[@]}
for (( i=0; i<${arraylength}; i++ ));
do
   echo "${array[$i]}"
done
Tuğrul Altun
источник
4

Еще проще, вы можете оперировать напрямую $@;)

Вот как можно передать список аргументов непосредственно из командной строки:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go
runlevel0
источник
1
Еще проще, так for stuff in "$@" ; do ...же, как for stuff ; do ...:)
ккм
1

Параллельное представление о том, что массив и $ @ практически одинаковы.

Код:

#!/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[@]}"

Входные данные:

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

Вывод:

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
источник
1

Важность двойных кавычек стоит подчеркнуть. Предположим, что аргумент содержит пробел.

Код:

#!/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

Вывод:

> ./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.
> 
Якоб Вегелин
источник