Kami biasanya menggunakan $@
untuk mewakili semua argumen kecuali $ 0. Namun, saya tidak tahu apa itu struktur data $@
.
Mengapa itu berperilaku berbeda dengan $*
ketika termasuk dalam kutipan ganda, adakah yang bisa memberi saya penjelasan tingkat juru?
Itu bisa diulang untuk loop, jadi sepertinya array. Namun, itu juga dapat bergema sepenuhnya dengan sederhana echo $@
, jika itu adalah array, hanya elemen pertama yang akan ditampilkan. Karena keterbatasan shell, saya tidak dapat menulis kode percobaan lagi untuk melakukannya.
Perbedaan antara posting ini : Posting ini menunjukkan bagaimana $@
berperilaku berbeda dari $*
. Tapi saya bertanya-tanya tentang tipe data $@
. Shell sebagai bahasa yang menafsirkan, seperti Python, harus mewakili data menurut serangkaian tipe dasar. Atau dengan kata lain, saya ingin tahu bagaimana $ @ disimpan dalam memori komputer.
Apakah itu string, string multi-line atau array?
Jika ini adalah tipe data unik, apakah mungkin untuk mendefinisikan variabel khusus sebagai turunan dari tipe ini?
printf '%s\n' "$@"
danprintf '%s\n' "$*"
. Theecho
utilitas hanya output argumen, tidak peduli apakah mereka satu atau banyak. Keduanya array (dari string), tetapi mereka berperilaku berbeda ketika dikutip ganda. Jika salah satu adalah string multi-line, maka mereka tidak akan dapat menyimpan string multi-line (yang mereka bisa). Tidak jelas masalah apa yang Anda coba selesaikan.@var
variabel dalam Perl, dalam hal penyimpanan yang mendasarinya. Dari sudut pandang program Perl biasa, itu tidak terlalu penting, selain itu dapat diakses sebagai array / daftar (dan fakta bahwa ada konteks di mana daftar diharapkan).Jawaban:
Itu dimulai sebagai peretasan di shell Bourne. Dalam shell Bourne, pemisahan kata IFS dilakukan (setelah tokenisasi) pada semua kata dalam konteks daftar (argumen baris perintah atau kata-kata
for
loop loop aktif). Jika Anda memiliki:Itu baris kedua akan tokenised di 3 kata,
$var
akan diperluas, dan membagi + gumpal akan dilakukan pada semua tiga kata, sehingga Anda akan berakhir berjalaned
dengant
,f
,le.txt
,f
,le2.txt
sebagai argumen.Mengutip bagian dari itu akan mencegah split + glob. Shell Bourne awalnya ingat karakter mana yang dikutip dengan mengatur bit ke-8 pada mereka secara internal (yang berubah kemudian ketika Unix menjadi 8bit bersih, tetapi shell masih melakukan sesuatu yang mirip dengan mengingat byte mana yang dikutip).
Keduanya
$*
dan$@
merupakan gabungan dari parameter posisi dengan ruang di antaranya. Tetapi ada proses khusus$@
ketika di dalam tanda kutip ganda. Jika$1
terkandungfoo bar
dan$2
terkandungbaz
,"$@"
akan berkembang ke:(dengan
^
s di atas menunjukkan karakter mana yang memiliki set bit ke-8). Di mana ruang pertama dikutip (memiliki set bit ke-8) tetapi bukan yang kedua (yang ditambahkan di antara kata-kata).Dan itu adalah pemisahan IFS yang menangani pemisahan argumen (dengan asumsi karakter spasi
$IFS
seperti apa adanya secara default). Itu mirip dengan bagaimana$*
diperluas dalam pendahulunya shell Mashey (itu sendiri didasarkan pada shell Thomson, sementara shell Bourne ditulis dari awal).Itu menjelaskan mengapa di shell Bourne awalnya
"$@"
akan memperluas ke string kosong, bukan apa-apa sama sekali ketika daftar parameter posisi kosong (Anda harus bekerja dengan itu${1+"$@"}
), mengapa tidak menyimpan parameter posisi kosong dan mengapa"$@"
tidak bekerja ketika$IFS
tidak mengandung karakter spasi.Tujuannya adalah untuk dapat meneruskan daftar argumen kata demi kata ke perintah lain, tetapi itu tidak berfungsi dengan baik untuk daftar kosong, untuk elemen kosong atau ketika
$IFS
tidak mengandung ruang (dua masalah pertama akhirnya diperbaiki di versi yang lebih baru) ).Shell Korn (yang menjadi dasar spesifikasi POSIX) mengubah perilaku itu dalam beberapa cara:
edit
ataufile.txt
dalam contoh di atas)$*
dan$@
digabung dengan karakter pertama dari$IFS
atau spasi ketika$IFS
kosong kecuali bahwa untuk kutipan"$@"
, bahwa joiner tidak dikutip seperti dalam shell Bourne, dan untuk kutip dikutip"$*"
ketikaIFS
kosong, parameter posisi ditambahkan tanpa pemisah.${array[@]}
${array[*]}
mengingatkan Bourne$*
dan$@
tetapi mulai pada indice 0 bukannya 1, dan jarang (lebih seperti array asosiatif) yang berarti$@
tidak dapat benar-benar diperlakukan sebagai array ksh (bandingkan dengancsh
/rc
/zsh
/fish
/ diyash
mana$argv
/$*
normal) array)."$@"
ketika$#
0 sekarang diperluas ke tidak ada alih-alih string kosong,"$@"
berfungsi saat$IFS
tidak mengandung spasi kecuali saatIFS
kosong. Tanda kutip$*
tanpa wildcard diperluas ke satu argumen (di mana parameter posisi digabungkan dengan spasi) saat$IFS
kosong.ksh93 memperbaiki beberapa masalah yang tersisa di atas. Dalam ksh93,
$*
dan$@
memperluas ke daftar parameter posisi, dipisahkan terlepas dari nilai$IFS
, dan kemudian membagi + globbed + penjepit diperluas dalam konteks daftar,$*
bergabung dengan byte pertama (bukan karakter) dari$IFS
,"$@"
dalam konteks daftar memperluas ke daftar parameter posisi, terlepas dari nilai$IFS
. Dalam konteks non-daftar, seperti divar=$@
,$@
digabung dengan spasi terlepas dari nilai$IFS
.bash
Array dirancang setelah ksh. Perbedaannya adalah:$IFS
alih-alih untuk byte$*
ketika tidak dikutip dalam konteks non-daftar saat$IFS
kosong.Sementara spec POSIX dulunya cukup kabur, sekarang lebih atau kurang menentukan perilaku bash.
Ini berbeda dari array normal di dalam
ksh
ataubash
di dalam:"${@:0}"
yang mencakup$0
(bukan parameter posisi, dan dalam fungsi memberi Anda nama fungsi atau tidak tergantung pada shell dan bagaimana fungsi itu didefinisikan)).shift
dapat digunakan.Di
zsh
atau diyash
mana array adalah array normal (tidak jarang, indeks dimulai pada satu seperti di semua shell lain tetapi ksh / bash),$*
diperlakukan sebagai array normal.zsh
memiliki$argv
sebagai alias untuknya (untuk kompatibilitas dengancsh
).$*
sama dengan$argv
atau${argv[*]}
(argumen digabungkan dengan karakter pertama$IFS
tetapi masih dipisahkan dalam konteks daftar)."$@"
suka"${argv[@]}"
atau"${*[@]}"}
mengalami pemrosesan khusus gaya Korn.sumber
Ini adalah parameter khusus yang diperluas ke nilai-nilai parameter posisi ... Tapi itu menarik tentang terminologi.
Kita dapat melihat parameter posisi sebagai bagian dari
$@
, sehingga ia memiliki sejumlah elemen berbeda ($1
,$2
...), yang dapat diakses secara independen dan diberi nama dengan bilangan asli berturut-turut. Itu membuatnya menjadi sesuatu yang biasanya disebut array.Sintaksnya agak aneh, dan bahkan terbatas. Tidak ada cara untuk memodifikasi elemen tunggal array secara individual. Sebaliknya, semuanya harus ditetapkan sekaligus. (Anda dapat menggunakan
set -- "$@" foo
untuk menambahkan nilai, atauset -- "${@:1:2}" foo "${@:3}"
untuk menambahkan nilai di tengah. Tetapi Anda dalam kedua kasus Anda harus menuliskan seluruh daftar yang dihasilkan.)Karena mereka didefinisikan untuk berperilaku berbeda.
Jika Anda maksudkan fakta yang
a=(foo bar asdf); echo $a
akan menghasilkan keluaran yang adilfoo
, maka ini sebagian besar merupakan kekhasan dari sintaks shell, dan fakta bahwa array bernama ksh-style dibuat lebih lambat daripada parameter posisional dan$@
. Plain$a
adalah sama${a[0]}
sehingga memiliki makna yang kompatibel dengan nilai skalar tunggal, terlepas dari apakaha
array atau variabel skalar sederhana.The
@
tanda mengacu pada seluruh daftar digunakan kembali dengan nama array dalam bahwa"${a[@]}"
adalah cara untuk mendapatkan seluruh daftar. Dibandingkan dengan array bernama, dengan$@
, kurung dan kurung yang tidak perlu dan nama hanya dilewati.Itu tergantung pada implementasinya, Anda harus melihat kode sumber dari shell tertentu yang Anda pedulikan.
Array, kebanyakan. Meskipun berbeda dari array bernama ksh-style, karena mereka dapat memiliki bilangan bulat non-negatif yang sewenang-wenang sebagai indeks, tidak hanya yang berturut-turut sama dengan
$@
. (Yaitu, array bernama bisa jarang, dan memiliki misalnya indeks1
,3
dan4
, dengan0
dan2
hilang. Itu tidak mungkin dengan parameter posisi.)Ini bukan string tunggal, karena dapat diperluas ke elemen yang berbeda, dan memanggil elemen garis juga tidak benar, karena variabel reguler apa pun, atau salah satu parameter posisi (elemen
$@
) juga dapat berisi baris baru.Tidak. Tapi array bernama mungkin lebih berguna.
sumber
$@
bukan struktur data, itu salah satu dari beberapa fungsi / operator untuk memperluas struktur data parameter-posisi.