Mengakses baris perintah bash args $ @ vs $ *

327

Dalam banyak pertanyaan SO dan tutorial bash, saya melihat bahwa saya dapat mengakses argumen baris perintah dalam skrip bash dalam dua cara:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

Yang mengakibatkan:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

Apa perbedaan antara $*dan $@?
Kapan seseorang harus menggunakan yang pertama dan kapan akan menggunakan yang kedua?

Oz123
sumber
lihat jawaban ini: stackoverflow.com/a/842325/671366
codeling
analisis statis dalam IntelliJ memperlakukan echo "something $@"sebagai kesalahan
Alex Cohn

Jawaban:

437

Perbedaannya muncul ketika parameter khusus dikutip. Biarkan saya menggambarkan perbedaan:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

satu contoh lebih lanjut tentang pentingnya mengutip: perhatikan ada 2 spasi antara "arg" dan nomornya, tetapi jika saya gagal mengutip $ word:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

dan dalam bash, "$@"adalah daftar "default" untuk beralih:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3
glenn jackman
sumber
65
+1 Saya selalu berpikir konsep ini paling baik ditunjukkan oleh contoh sederhana, di mana manual bash benar-benar kurang.
chepner
5
Apakah ada kemungkinan penggunaan, kapan $*atau "$*"mungkin diperlukan, & tujuannya tidak dapat dilayani oleh $@atau "$@"?
anishsane
5
Versi mana yang lebih cocok untuk skrip "wrapper", di mana parameter skrip perlu menjadi parameter untuk perintah baru?
Segfault
7
@Segfault, dalam hal ini, selalu memilih "$@"dengan tanda kutip.
glenn jackman
2
Jawaban ini berisi contoh-contoh berguna tetapi akan lebih baik jika juga menjelaskan mekanisme di belakang mereka. Mengapa ini bekerja seperti ini?
Lii
255

Tabel ikhtisar berguna yang berguna dari Bash Hackers Wiki :

$ * versus $ @ tabel

cdi mana di baris ketiga adalah karakter pertama $IFS, Pemisah Bidang Internal, variabel shell.

Jika argumen akan disimpan dalam variabel skrip dan argumen diharapkan berisi spasi, saya dengan sepenuh hati merekomendasikan menggunakan "$*"trik dengan pemisah bidang internal yang $IFSdiatur ke tab .

Serge Stroobandt
sumber
42
... di mana "c" adalah karakter pertama dari $ IFS
glenn jackman
39
... dan $IFSsingkatan dari "Internal Field Separator."
Serge Stroobandt
Berikut ini sebuah contoh , yang mencakup input yang dikutip. Masukan juga penting!
Serge Stroobandt
Katakanlah saya ingin membuat skrip wrapper yang tidak melakukan apa-apa selain meniru fungsi perintah yang dibungkus. Sintaks mana yang harus saya gunakan untuk meneruskan argumen dari skrip wrapper ke perintah internal?
Marinos An
44

$ *

Perluas ke parameter posisi, mulai dari satu. Ketika ekspansi terjadi dalam tanda kutip ganda, itu berkembang menjadi satu kata dengan nilai setiap parameter dipisahkan oleh karakter pertama dari variabel khusus IFS. Artinya, "$ *" setara dengan "$ 1c $ 2c ...", di mana c adalah karakter pertama dari nilai variabel IFS. Jika IFS tidak disetel, parameter dipisahkan oleh spasi. Jika IFS adalah nol, parameter bergabung tanpa pemisah yang mengintervensi.

$ @

Perluas ke parameter posisi, mulai dari satu. Ketika ekspansi terjadi dalam tanda kutip ganda, setiap parameter meluas ke kata yang terpisah. Yaitu, "$ @" sama dengan "$ 1" "$ 2" ... Jika ekspansi yang dikutip ganda terjadi dalam sebuah kata, ekspansi dari parameter pertama digabungkan dengan bagian awal dari kata aslinya, dan ekspansi parameter terakhir bergabung dengan bagian terakhir dari kata aslinya. Ketika tidak ada parameter posisi, "$ @" dan $ @ perluas apa-apa (mis., Mereka dihapus).

Sumber: Bash man

Muffo
sumber
15

$ @ sama dengan $ *, tetapi setiap parameter adalah string yang dikutip, yaitu, parameter dilewatkan secara utuh, tanpa interpretasi atau ekspansi. Ini berarti, antara lain, bahwa setiap parameter dalam daftar argumen dilihat sebagai kata yang terpisah.

Tentu saja, "$ @" harus dikutip.

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST

rkosegi
sumber
1

Contoh ini dapat menyoroti perbedaan antara "at" dan "asterix" saat kami menggunakannya. Saya menyatakan dua array "buah-buahan" dan "sayuran"

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

Lihat hasil berikut kode di atas:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion
stefansson
sumber
7
Secara ilmiah, tomat adalah buah.
Randy
1
Kamu punya hak! "Dalam botani, buah adalah struktur bantalan biji pada tanaman berbunga (juga dikenal sebagai angiospermae) yang terbentuk dari ovarium setelah berbunga." en.wikipedia.org/wiki/Fruit
stefansson
@Randy: secara ilmiah, semua buah adalah sayuran (ini adalah sinonim untuk "tanaman").
Cris Luengo
@CrisLuengo bid'ah! :)
Randy