Перетворити аргументи командного рядка в масив в Bash


161

Як перетворити аргументи командного рядка в масив скриптів 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

Відповіді:


207

Насправді аргументи вашого командного рядка вже практично схожі на масив. Принаймні, ви можете ставитися до $@змінної так само, як до масиву. Однак, ви можете перетворити його у фактичний масив на зразок цього:

myArray=( "$@" )

Якщо ви просто хочете ввести деякі аргументи і ввести їх у $@значення, використовуйте set:

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

Розуміння, як використовувати структуру аргументів, особливо корисне в POSIX sh, який не має нічого іншого, як масив.


2
Дякую! Чудово працює! Якраз збирався запитати, як перевірити нульові аргументи та призначити значення масиву за замовчуванням, і $ # ідеально підходить для цього!
Суман

1
setдозволяє встановлювати позиційні параметри для області. Це також дозволяє встановити параметри оболонки. Ви можете зробити це set foo, що означатиме $1розширення до "foo", але якщо ваші параметри починаються з тире set, припустимо, ви маєте намір встановити параметр оболонки. Подвійний тире гарантує, що всі наступні параметри інтерпретуються як встановлені позиційні параметри.
kojiro

12
Один готч: echo $@надрукує всі аргументи, але echo $myArrayнадрукує лише перший елемент. Щоб побачити їх усіх, використовуйте echo ${myArray[@]}.
z0r

4
@ z0r Якщо ви не ставите подвійних лапок навколо цих розширень, то bash повторно їх розщепить і, можливо, втратить значення.
kojiro

Правильно, загальний спосіб "сплавити" масив та використовувати кожен елемент - це "${myArray[@]}". Якщо ви хочете провести цикл через масив, вам потрібно цитати, щоб уникнути поділу окремих елементів на IFS
BallpointBen

66

Можливо, це може допомогти:

myArray=("$@") 

також ви можете повторити аргументи, опустивши "in":

for arg; do
   echo "$arg"
done

буде рівнозначним

for arg in "${myArray[@]}"; do
   echo "$arg"
done

3
Питання для новачків: Як баш знає, що поставити в argполе - це заздалегідь визначена змінна? ${var}розширено до змісту var. ${var[n]}розширюється до вмісту елемента nмасиву var. Чи ${var[@]}розширюється тоді весь масив, тобто ${var[0]} ${var[1]} ... ${var[n]}nіндексом останнього елемента)?
Крістіан

4
[for] без [in] перетворить аргумент на масив $ @ ($ 1, $ 2 тощо). Яку можна встановити також за допомогою команди [set], наприклад set - arg1 arg2
Nahuel Fouilleul

17

Власне, до списку параметрів можна отримати доступ і $1 $2 ...т. Д.
Що точно еквівалентно:

${!i}

Отже, список параметрів можна змінити за допомогою набору,
і ${!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

4

Простіше, але ви можете працювати безпосередньо на $@;)

Ось як зробити список аргументів безпосередньо з підказки:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go

1
Ще простіше, те for stuff in "$@" ; do ...саме, що for stuff ; do ...:)
kkm

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

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.
> 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.