Czy wszystkie zmienne są przechowywane w pamięci jako ciąg w bash?

14

Powiedzmy, że utworzyłem następujące zmienne:

s=John
i=12345
f=3.14

Czy wszystkie te zmienne są przechowywane w pamięci jako ciąg, czy też bashmają inne typy danych?

użytkownik268325
źródło
1
Po prostu z braku zainteresowania, dlaczego miałoby to mieć znaczenie? Naprawdę nie dbam o to, czy były przechowywane jako tekst suahili, o ile nie wpłynęło to na funkcjonalność języka (wpływ na wydajność może być problemem, ale jeśli to ważne, są lepszymi narzędziami w twoim arsenale niż bash).
2
@paxdiablo To nie ma znaczenia, po prostu pytam z ciekawości, ponieważ wszystkie inne języki programowania / skryptów, które znam (na przykład: Java, C ++, JavaScript, PHP itp.) mają unikalną reprezentację pamięci dla każdego typu danych , dlatego interesujące jest zobaczenie języka skryptowego, który ma tylko jedną reprezentację pamięci dla wszystkich typów danych.
user268325

Odpowiedzi:

16

Zmienne Bash są bez typu .

W przeciwieństwie do wielu innych języków programowania, Bash nie segreguje swoich zmiennych według „typu”. Zasadniczo zmienne Bash są ciągami znaków, ale w zależności od kontekstu Bash pozwala na operacje arytmetyczne i porównania zmiennych. Czynnikiem decydującym jest to, czy wartość zmiennej zawiera tylko cyfry.

Jak mówi inna odpowiedź , istnieje pewna słaba forma pisania na klawiaturze declare.

Jest to bardzo słaba forma pisania [1] dostępna w niektórych językach programowania.

Zobacz przykład:

declare -i number
# The script will treat subsequent occurrences of "number" as an integer.     

number=3
echo "Number = $number"     # Number = 3

number=three
echo "Number = $number"     # Number = 0
# Tries to evaluate the string "three" as an integer.

Bibliografia:

roaima
źródło
13

Bash zasadniczo ma proste zmienne skalarne, tablice i tablice asocjacyjne. Ponadto, declarewbudowane skalary mogą być oznaczone jako liczby całkowite . Z punktu widzenia programisty / użytkownika powłoki zmienne łańcuchowe działają jak łańcuchy, zmienne całkowite działają jako liczby całkowite, a tablice odpowiednio do ich typu. Wewnętrzne wdrożenie nie jest zbyt istotne.


Ale jeśli chcemy wiedzieć, jak dane są faktycznie przechowywane w pamięci, musimy zbadać kod źródłowy, aby zobaczyć, co faktycznie robi program.

W Bash 4.4 skalary są przechowywane jako ciągi, niezależnie od znacznika liczby całkowitej. Jest to widoczne w definicji struct variable/ SHELL_VARtypedef oraz w funkcjimake_variable_value , która jawnie tłumaczy liczby całkowite na ciągi do przechowywania.

Tablice są przechowywane na czymś, co wygląda na listę połączoną ( array.h), a tablice asocjacyjne jako tabele skrótów. Wartości w nich zapisane są ponownie jako ciągi znaków. Wybór połączonej listy dla tablic może wydawać się dziwny, ale ponieważ tablice mogą być rzadkie, a indeksy mogą być dowolnymi liczbami, niezależnie od tego, ile elementów zawiera tablica, wybór projektu jest nieco łatwiejszy do zrozumienia.

Jednak kod zawiera również definicję nieużywanegounion _value , z polami na liczby całkowite, liczby zmiennoprzecinkowe, a także wartości ciągu. Jest oznaczony w komentarzu jako „na przyszłość”, więc możliwe jest, że niektóre przyszłe wersje Bash będą przechowywać różne rodzaje skalarów w ich rodzimych formach.

ilkkachu
źródło
1

W moim życiu nie mogę tego znaleźć w wielu słowach, ale tak to rozumiem.

Bash jest interpretatorem, a nie kompilatorem i reprezentuje wszystkie zmienne jako ciągi znaków. Stąd cały wysiłek i nacisk związany z różnego rodzaju ekspansjami.

Bash przechodzi przechodzi wszystkie nazwanych zmiennych declarejako ciągi z atrybutów , które kontrolują w jaki sposób, że zmienna ma być rozszerzony przez declarepodczas przechowywania.

banana=yellow              #no call to declare
declare -p banana
declare -- banana="yellow" #but declare was invoked with --

declare -i test=a          #arithmetic expansion to null/zero
declare -p test
declare -i test="0"

declare -i test2=5+4       #successful arithmetic expansion
declare -p test2
declare -i test2="9"

declare -i float=99.6      #arithmetical expansion fails due to syntax
bash: declare: 99.6: syntax error: invalid arithmetic operator (error token is ".6")

nofloat=99.9
declare -p nofloat
declare -- nofloat"99.6"   #Success because arithmetical expansion not invoked

declare -a a               #variable is marked as a placeholder to receive an array
declare -p a
declare -a a

a[3]=99                    #array elements are appended
a[4]=99
declare -p a
declare -a a=([3]="99" [4]="99") 

declare -A newmap          #same as -a but names instead of numbers
newmap[name]="A Bloke"
newmap[designation]=CFO
newmap[company]="My Company"
declare -p newmap
declare -A newmap=([company]="My Company" [name]="A Bloke" [designation]="CFO" )

I oczywiście

declare -ia finale[1]=9+16
declare -p finale
declare -ai finale=([1]="25")

Coda tego polega na tym, że nawet jeśli declarema wewnętrzną reprezentację, która zmienia się wraz z flagami atrybutów, ciągi są wszystkim, co bash widzi lub chce zobaczyć.

bu5hman
źródło
0

Ta strona zawiera obszerny przewodnik na temat pisania zmiennych w Bash. Ta sekcja zawiera więcej informacji na temat declarewbudowanego polecenia. Ten fragment kodu z tego linku może być interesujący:

[bob in ~] declare -i VARIABLE=12

[bob in ~] VARIABLE=string

[bob in ~] echo $VARIABLE
0

[bob in ~] declare -p VARIABLE
declare -i VARIABLE="0"

Oto manstrona dladeclare .

Tanner Babcock
źródło
0

To nie ma znaczenia.

Jedynym sposobem interakcji ze zmiennymi Bash jest użycie Bash, więc nie można zauważyć żadnej różnicy, w jaki sposób zmienne są przechowywane w pamięci, ponieważ nigdy nie można uzyskać do nich dostępu bezpośrednio przez pamięć , zawsze należy poprosić Bash o ich wartość i atakujących może następnie przełożyć je w jakikolwiek sposób chce wyglądać tak, jakby był przechowywany w żaden szczególny sposób.

W rzeczywistości, może nawet nie być przechowywane w pamięci w ogóle . Nie wiem, jak sprytne są popularne implementacje Basha, ale przynajmniej w prostych przypadkach można przynajmniej ustalić, czy zmienna zostanie użyta i / lub czy zostanie zmodyfikowana, i zoptymalizować ją całkowicie lub wbudować.

Jörg W Mittag
źródło
Myślę, że celem pytania była raczej reprezentacja niż lokalizacja
bu5hman
2
Chodzi mi o to, że nie możesz znać przedstawienia, ponieważ nie możesz go zaobserwować. Jest to więc nieistotne i może się zmienić bez Twojej uwagi. Po prostu niemożliwe jest określenie, jaką reprezentację może wybrać Bash. Możesz zagłębić się w kod źródłowy implementacji i sprawdzić, jaką reprezentację wybierze, ale może zmienić reprezentację jutro w następnej wersji łaty i nie będzie sposobu, aby wiedzieć.
Jörg W Mittag
Zmienne Schroedingersa? Zgadzam się z tobą zasadniczo, że podstawowa reprezentacja jest nieistotna (patrz moja odpowiedź), ale używając bash skutecznie „kodujemy interfejs”, a reprezentacja na interfejsie jest rygorystyczna.
bu5hman
2
Tak, ale pytanie nie dotyczy reprezentacji na granicy interfejsu, ale konkretnie tego, w jaki sposób są one „przechowywane w pamięci”. I na to pytanie odpowiedziałbym: nie wiemy, nie możemy i nie powinniśmy wiedzieć.
Jörg W Mittag
Które parafrazują ostatnią linijkę mojego własnego posta ..... jak już powiedziałem, zgadzamy się ...... i biorąc pod uwagę przedstawiciela PO i charakter pytania, myślę, że otrzymają rozsądne oceny za pracę domową, ktokolwiek dostaje cytat ;-).
bu5hman