Konversi argumen baris perintah ke dalam array di Bash

162

Bagaimana cara mengubah argumen baris perintah menjadi larik skrip bash?

Saya ingin mengambil ini:

./something.sh arg1 arg2 arg3

dan mengubahnya menjadi

myArray=( arg1 arg2 arg3 )

sehingga saya bisa menggunakan myArray untuk digunakan lebih lanjut dalam skrip.

Posting SO sebelumnya ini hampir selesai, tetapi tidak membahas cara membuat array: Bagaimana cara mengurai argumen baris perintah di Bash?

Saya perlu mengubah argumen menjadi array skrip bash biasa; Saya menyadari bahwa saya dapat menggunakan bahasa lain (Python, misalnya) tetapi perlu melakukan ini di bash. Saya kira saya sedang mencari fungsi "tambahkan" atau yang serupa?

UPDATE: Saya juga ingin bertanya bagaimana memeriksa nol argumen dan menetapkan nilai array default, dan terima kasih atas jawaban di bawah ini, dapat membuat ini berfungsi:

if [ "$#" -eq 0 ]; then
  myArray=( defaultarg1 defaultarg2 )
else
  myArray=( "$@" )
fi
Suman
sumber

Jawaban:

208

Sebenarnya argumen baris perintah Anda sudah hampir seperti array. Setidaknya, Anda bisa memperlakukan $@variabel seperti array. Yang mengatakan, Anda bisa mengubahnya menjadi array aktual seperti ini:

myArray=( "$@" )

Jika Anda hanya ingin mengetik beberapa argumen dan memasukkannya ke dalam $@nilai, gunakan set:

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

Memahami bagaimana menggunakan struktur argumen sangat berguna dalam POSIX sh, yang tidak memiliki yang lain seperti array.

kojiro
sumber
2
Terima kasih! Bagus sekali! Baru saja akan bertanya bagaimana memeriksa argumen nol dan menetapkan nilai array default, dan $ # berfungsi sempurna untuk itu!
Suman
1
setmemungkinkan Anda untuk mengatur parameter posisi untuk ruang lingkup. Ini juga memungkinkan Anda mengatur opsi shell. Anda dapat melakukannya set foo, yang berarti $1memperluas ke "foo", tetapi jika parameter Anda mulai dengan tanda hubung setakan menganggap Anda bermaksud mengatur opsi shell. Tanda hubung ganda memastikan bahwa semua parameter berikut diinterpretasikan sebagai parameter posisi yang akan ditetapkan.
kojiro
12
Satu gotcha: echo $@akan mencetak semua argumen, tetapi echo $myArrayhanya akan mencetak elemen pertama. Untuk melihat semuanya, gunakan echo ${myArray[@]}.
z0r
4
@ z0r Jika Anda tidak menempatkan tanda kutip ganda di sekitar ekspansi itu maka bash akan menimpanya kembali, dan mungkin kehilangan makna.
kojiro
Benar, cara umum untuk "memerciki" sebuah array dan menggunakan setiap elemen adalah "${myArray[@]}". Jika Anda ingin mengulang-ulang array, Anda perlu tanda kutip untuk menghindari pemisahan elemen individual pada IFS
BallpointBen
66

Mungkin ini bisa membantu:

myArray=("$@") 

Anda juga dapat mengulangi argumen dengan menghilangkan 'in':

for arg; do
   echo "$arg"
done

akan setara

for arg in "${myArray[@]}"; do
   echo "$arg"
done
Nahuel Fouilleul
sumber
3
Pertanyaan pemula: Bagaimana bash tahu apa yang harus dimasukkan ke dalam argbidang - apakah itu variabel yang telah ditentukan? ${var}diperluas ke konten var. ${var[n]}diperluas ke konten elemen narray var. Apakah ${var[@]}kemudian memperluas seluruh array, yaitu ${var[0]} ${var[1]} ... ${var[n]}(dengan nmenjadi indeks elemen terakhir)?
Christian
4
[untuk] tanpa [di] akan mengulangi argumen array $ @ ($ 1, $ 2, dll). Yang dapat diatur juga dengan perintah [set], misalnya set - arg1 arg2
Nahuel Fouilleul
17

Sebenarnya daftar parameter dapat diakses dengan $1 $2 ...dll.
Yang persis sama dengan:

${!i}

Jadi, daftar parameter dapat diubah dengan set,
dan ${!i}merupakan cara yang benar untuk mengaksesnya:

$ 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

Untuk kasus spesifik Anda, ini dapat digunakan (tanpa perlu array), untuk mengatur daftar argumen ketika tidak ada yang diberikan:

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

yang diterjemahkan ke ungkapan yang lebih sederhana ini:

[ "$#" == "0" ] && set -- defaultarg1 defaultarg2
Yaron
sumber
Bukankah seharusnya contoh gema: echo "$#" "$i+1" "${!i}";untuk mendapatkan output persis seperti yang ditunjukkan?
Zael
6

Ini adalah penggunaan lain:

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

Lebih mudah lagi, Anda dapat beroperasi secara langsung $@ ;)

Inilah cara melakukan pass daftar args langsung dari prompt:

function echoarg { for stuff in "$@" ; do echo $stuff ; done ; } 
    echoarg Hey Ho Lets Go
    Hey
    Ho
    Lets
    Go
runlevel0
sumber
1
Lebih mudah lagi, for stuff in "$@" ; do ...sama seperti for stuff ; do ...:)
kkm
1

Tampilan berdampingan tentang bagaimana array dan $ @ praktis sama.

Kode:

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

Memasukkan:

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

Keluaran:

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
sumber
1

Pentingnya kutipan ganda patut ditekankan. Misalkan argumen berisi spasi putih.

Kode:

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

Keluaran:

> ./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
sumber