Jaka jest struktura danych $ @ w powłoce?


13

Zwykle $@reprezentujemy wszystkie argumenty oprócz 0. Nie wiem jednak, jaka $@jest struktura danych .

Dlaczego zachowuje się inaczej w $*przypadku podwójnego cytatu, czy ktoś mógłby mi wyjaśnić na poziomie tłumacza?

Może być iterowany w pętli for, więc wygląda na tablicę. Jednak można go również w całości powtórzyć za pomocą prostej echo $@, jeśli jest to tablica, zostanie pokazany tylko pierwszy element. Z powodu ograniczenia powłoki nie mogę napisać więcej kodu eksperymentu, aby go wykonać.

Różnica między tym postem : Ten post pokazuje, jak $@się inaczej zachowuje $*. Ale zastanawiam się nad typem danych $@. Shell jako język interpretacyjny, podobnie jak Python, powinien reprezentować dane zgodnie z szeregiem podstawowych typów. Innymi słowy, chcę wiedzieć, jak $ @ przechowywane w pamięci komputera.

Czy jest to ciąg, ciąg wielu linii czy tablica?

Jeśli jest to unikalny typ danych, czy można zdefiniować zmienną niestandardową jako instancję tego typu?



@Haxiel, nie sądzę, napisałem ich różnicę na dole mojego postu.
davmos

Lepiej byłoby ci służyć, testując różnicę w wynikach za pomocą printf '%s\n' "$@"i printf '%s\n' "$*". echoNarzędzie po prostu wyprowadza swoje argumenty, nie ważne czy są one jednego lub wielu. Obie są tablicami (ciągów), ale zachowują się inaczej, gdy są podwójnie cytowane. Gdyby którykolwiek był łańcuchem wieloliniowym, nie byliby w stanie przechowywać łańcuchów wieloliniowych (co mogą). Nie jest jasne, jaki problem próbujesz rozwiązać.
Kusalananda

2
Twoje pytanie jest równoważne z pytaniem, jaka @varzmienna jest w Perlu, pod względem podstawowej pamięci. Z punktu widzenia zwykłego programu Perla nie ma to tak naprawdę znaczenia, poza tym, że jest on dostępny jako tablica / lista (oraz fakt, że istnieją konteksty, w których oczekiwana jest lista).
Kusalananda

Odpowiedzi:


16

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 forpętli). Gdybyś miał:

IFS=i var=file2.txt
edit file.txt $var

Że druga linia będzie tokenised w 3 słowach, $varbędzie rozszerzona i podzielonego + glob byłyby wykonywane na wszystkich trzech słowach, tak by skończyć uruchomiony edz t, f, le.txt, f, le2.txtjako 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 $1zawarte foo bari $2zawarte 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 $IFStaki, 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 $IFSnie 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 $IFSnie 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 editlub file.txtw powyższym przykładzie)
  • $*i $@są łączone z pierwszym znakiem $IFSlub spacją, gdy $IFSjest 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 IFSjest 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/ yashgdzie $argv/ $*jest normalne tablice).
  • Puste elementy są zachowane.
  • "$@"kiedy $#0 jest teraz interpretowane jako nic zamiast pustego ciągu, "$@"działa, gdy $IFSnie zawiera spacji, z wyjątkiem gdy IFSjest pusty. $*Bez cudzysłowu bez symboli zastępczych rozwija się do jednego argumentu (gdzie parametry pozycyjne są łączone ze spacją), gdy $IFSjest 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.

bashTablice są zaprojektowane po ksh. Różnice są następujące:

  • brak rozwinięcia nawiasów klamrowych po niecytowanym rozwinięciu
  • pierwszy znak $IFSzamiast 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 $IFSjest 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 kshlub bashw 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 zshlub yashgdzie 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. zshma $argvjako alias (dla kompatybilności z csh). $*jest taki sam jak $argvlub ${argv[*]}(argumenty połączone z pierwszym znakiem, $IFSale nadal rozdzielone w kontekstach listy). "$@"polubić "${argv[@]}"lub "${*[@]}"}poddać specjalnej obróbce w stylu Korna.


8

Nie wiem jednak, jaka $@jest struktura danych .

Jest to specjalny parametr, który rozszerza się na wartości parametrów pozycyjnych ... Ale to nie jest w porządku z terminologią.

Możemy wyświetlać parametry pozycyjne jako części $@, więc ma on wiele odrębnych elementów ( $1, $2...), do których można uzyskać dostęp niezależnie i które są nazywane kolejnymi liczbami naturalnymi. To sprawia, że ​​jest to coś, co zwykle nazywa się tablicą.

Składnia jest jednak nieco dziwna, a nawet ograniczona. Nie ma możliwości modyfikacji pojedynczego elementu tablicy indywidualnie. Zamiast tego wszystko musi być ustalone na raz. (Możesz użyć, set -- "$@" fooaby dodać wartość lub set -- "${@:1:2}" foo "${@:3}"dodać wartość na środku. Ale w obu przypadkach musisz zapisać całą wynikową listę).

Dlaczego zachowuje się inaczej w $*przypadku podwójnego cytatu,

Ponieważ są zdefiniowane, aby zachowywać się inaczej.

Jednak można go również w całości powtórzyć za pomocą prostej echo $@, jeśli jest to tablica, zostanie pokazany tylko pierwszy element.

Jeśli masz na myśli fakt, że a=(foo bar asdf); echo $awłaśnie wypisze dane wyjściowe foo, to jest to głównie dziwactwo składni powłoki oraz fakt, że nazwane tablice w stylu ksh powstały później niż parametry pozycyjne i $@. Zwykły $ajest taki sam, ponieważ ${a[0]}ma kompatybilne wstecz znaczenie pojedynczej wartości skalarnej, niezależnie od tego, czy ajest tablicą czy zwykłą zmienną skalarną.

@Znak odnoszący się do całej listy został użyty za wymienionych w tablicach, że "${a[@]}"jest sposób, aby uzyskać całą listę. W porównaniu do nazwanych tablic, $@niepotrzebne nawiasy klamrowe i nawiasy oraz nazwa są po prostu pomijane.

Innymi słowy, chcę wiedzieć, jak $@przechowywane w pamięci komputera.

To zależy od implementacji, musisz poszukać kodu źródłowego dowolnej powłoki, na której ci zależy.

Czy jest to ciąg, ciąg wielu linii czy tablica?

Głównie tablica. Chociaż różnią się od nazwanych tablic w stylu ksh, ponieważ mogą mieć dowolne nieujemne liczby całkowite jako indeksy, a nie tylko kolejne, jak z $@. (Oznacza to, że tablica może być nazwany rzadki i mieć np indeksów 1, 3a 4ze 0i 2brakuje. To nie jest to możliwe z parametrów pozycyjnych).

Nie jest to pojedynczy ciąg, ponieważ można go rozwinąć do odrębnych elementów, a wywoływanie linii elementów również nie jest właściwe, ponieważ dowolna zmienna regularna lub jeden z parametrów pozycyjnych (elementów $@) może również zawierać znaki nowej linii.

Jeśli jest to unikalny typ danych, czy można zdefiniować zmienną niestandardową jako instancję tego typu?

Nie. Ale tablice nazwane i tak są prawdopodobnie bardziej przydatne.


1
+1. TL: DR $@nie jest strukturą danych, jest jedną z niewielu funkcji / operatorów do rozszerzania struktury danych parametrów pozycyjnych.
Peter Cordes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.