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:
IFS=i var=file2.txt
edit file.txt $var
Itu baris kedua akan tokenised di 3 kata, $var
akan diperluas, dan membagi + gumpal akan dilakukan pada semua tiga kata, sehingga Anda akan berakhir berjalan ed
dengan t
, 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
terkandung foo bar
dan $2
terkandung baz
, "$@"
akan berkembang ke:
foo bar baz
^^^^^^^ ^^^
(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:
- Pemisahan IFS hanya dilakukan pada hasil ekspansi yang tidak dikutip (bukan pada kata-kata literal seperti
edit
atau file.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 "$*"
ketika IFS
kosong, parameter posisi ditambahkan tanpa pemisah.
- itu menambahkan dukungan untuk array, dan dengan
${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 dengan csh
/ rc
/ zsh
/ fish
/ di yash
mana $argv
/ $*
normal) array).
- Elemen-elemen yang kosong dipertahankan.
"$@"
ketika $#
0 sekarang diperluas ke tidak ada alih-alih string kosong, "$@"
berfungsi saat $IFS
tidak mengandung spasi kecuali saat IFS
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 di var=$@
, $@
digabung dengan spasi terlepas dari nilai $IFS
.
bash
Array dirancang setelah ksh. Perbedaannya adalah:
- tidak ada brace-ekspansi atas ekspansi yang tidak dikutip
- karakter pertama
$IFS
alih-alih untuk byte
- beberapa perbedaan sudut kasus seperti perluasan
$*
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
atau bash
di dalam:
- Indeks mulai dari 1 bukannya 0 (kecuali
"${@:0}"
yang mencakup $0
(bukan parameter posisi, dan dalam fungsi memberi Anda nama fungsi atau tidak tergantung pada shell dan bagaimana fungsi itu didefinisikan)).
- Anda tidak dapat menetapkan elemen secara individual
- itu tidak jarang, Anda tidak dapat menghapus elemen secara individual
shift
dapat digunakan.
Di zsh
atau di yash
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 dengan csh
). $*
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.