Zaczęło się od włamania do powłoki Bourne'a. W powłoce Bourne'a dzielono słowa IFS (po tokenizacji) na wszystkie słowa w kontekście listy (argumenty linii poleceń lub słowa na for
pętli). Gdybyś miał:
IFS=i var=file2.txt
edit file.txt $var
Że druga linia będzie tokenised w 3 słowach, $var
będzie rozszerzona i podzielonego + glob byłyby wykonywane na wszystkich trzech słowach, tak by skończyć uruchomiony ed
z t
, f
, le.txt
, f
, le2.txt
jako argumenty.
Cytowanie części tego zapobiegłoby podziałowi + globowi. Powłoka Bourne'a początkowo pamiętała, które znaki były cytowane, ustawiając na nich 8. bit (to zmieniło się później, gdy Unix stał się 8-bitowy czysty, ale powłoka nadal robiła coś podobnego, aby zapamiętać, który bajt był cytowany).
Zarówno $*
i $@
były konkatenacją pozycyjnych z przestrzeni między nimi. Ale było specjalne przetwarzanie, $@
kiedy wewnątrz podwójnych cudzysłowów. Jeśli $1
zawarte foo bar
i $2
zawarte baz
, "$@"
rozwija się do:
foo bar baz
^^^^^^^ ^^^
(z ^
powyższymi literami „s” wskazującymi, który ze znaków ma ustawiony 8. bit). Gdzie cytowano pierwszą spację (ustawiono 8 bit), ale nie drugą (ta dodawana pomiędzy słowami).
I to rozdzielenie IFS dba o rozdzielenie argumentów (zakładając, że znak spacji jest $IFS
taki, jaki jest domyślnie). Jest to podobne do tego, jak $*
zostało rozszerzone w swoim poprzedniku, powłoce Mashey (sama oparta na powłoce Thomsona, podczas gdy powłoka Bourne'a została napisana od zera).
To wyjaśnia, dlaczego w Bourne shell początkowo "$@"
rozwinie się do pustej struny zamiast w ogóle nic, gdy lista parametrów pozycyjnych była pusta (trzeba było obejść się ${1+"$@"}
), dlaczego nie trzymać puste parametry pozycyjne i dlaczego "$@"
didn działa, gdy $IFS
nie zawiera znaku spacji.
Chodziło o to, aby móc przekazać listę argumentów dosłownie do innego polecenia, ale to nie działało poprawnie dla pustej listy, pustych elementów lub gdy $IFS
nie zawierało spacji (pierwsze dwa problemy zostały ostatecznie naprawione w późniejszych wersjach ).
Powłoka Korna (na której oparta jest specyfikacja POSIX) zmieniła to zachowanie na kilka sposobów:
- Podział IFS odbywa się tylko na podstawie niecytowanych rozszerzeń (nie na dosłownych słowach takich jak
edit
lub file.txt
w powyższym przykładzie)
$*
i $@
są łączone z pierwszym znakiem $IFS
lub spacją, gdy $IFS
jest pusty, z wyjątkiem tego, że dla cudzysłowu "$@"
, ten łącznik nie jest cytowany jak w powłoce Bourne'a, a dla cudzysłowu, "$*"
gdy IFS
jest pusty, parametry pozycyjne są dodawane bez separatora.
- że dodatkowe wsparcie dla tablic, i
${array[@]}
${array[*]}
przypomina Bourne $*
i $@
lecz wychodząc z índice 0 zamiast 1, oraz fragmentarycznych (bardziej asocjacyjnych), które to środki $@
nie mogę być traktowane jako tablica ksh (porównaj z csh
/ rc
/ zsh
/ fish
/ yash
gdzie $argv
/ $*
jest normalne tablice).
- Puste elementy są zachowane.
"$@"
kiedy $#
0 jest teraz interpretowane jako nic zamiast pustego ciągu, "$@"
działa, gdy $IFS
nie zawiera spacji, z wyjątkiem gdy IFS
jest pusty. $*
Bez cudzysłowu bez symboli zastępczych rozwija się do jednego argumentu (gdzie parametry pozycyjne są łączone ze spacją), gdy $IFS
jest pusty.
ksh93 naprawił pozostałe kilka problemów powyżej. W ksh93, $*
i $@
rozszerza się do listy parametrów pozycyjnych, oddzielone niezależnie od wartości $IFS
, a następnie dalej podzielone + globbed + klamra rozszerzone w kontekście lista, $*
połączone z pierwszym bajcie (nie znaków) z $IFS
, "$@"
w kontekście lista rozwija się na liście parametrów pozycyjnych, niezależnie od wartości $IFS
. W kontekście innym niż lista, jak w var=$@
, $@
jest łączony ze spacją niezależnie od wartości $IFS
.
bash
Tablice są zaprojektowane po ksh. Różnice są następujące:
- brak rozwinięcia nawiasów klamrowych po niecytowanym rozwinięciu
- pierwszy znak
$IFS
zamiast zamiast bajtu
- niektóre różnice wielkości liter w rogach, takie jak rozszerzenie,
$*
gdy nie jest cytowany w kontekście innym niż lista, gdy $IFS
jest pusty.
Podczas gdy specyfikacja POSIX była dość niejasna, teraz mniej więcej określa zachowanie bash.
Różni się od zwykłych tablic w tym ksh
lub bash
w tym:
- Indeksy zaczynają się od 1 zamiast 0 (z wyjątkiem,
"${@:0}"
gdy zawiera $0
(nie parametr pozycyjny, a w funkcjach daje nazwę funkcji lub nie zależy od powłoki i sposobu jej zdefiniowania)).
- Nie można przypisywać elementów indywidualnie
- to nie jest rzadkie, nie można indywidualnie rozbroić elementów
shift
może być użyte.
W zsh
lub yash
gdzie tablice są normalnymi tablicami (nie rzadkimi, indeksy zaczynają się od jedności jak we wszystkich innych powłokach, ale ksh / bash), $*
są traktowane jak normalna tablica. zsh
ma $argv
jako alias (dla kompatybilności z csh
). $*
jest taki sam jak $argv
lub ${argv[*]}
(argumenty połączone z pierwszym znakiem, $IFS
ale nadal rozdzielone w kontekstach listy). "$@"
polubić "${argv[@]}"
lub "${*[@]}"}
poddać specjalnej obróbce w stylu Korna.