11

Say I created the following variables:

s=John
i=12345
f=3.14

Are all of these variables stored in memory as string, or does bash have other data types?

  • 1
    Just out of interest, why would it matter? I really couldn't care less if they were stored as Swahili text as long as it didn't affect the functionality of the language (affecting performance may be an issue but, if that's important, they're are better tools in your arsenal than bash). – user14408 Jan 2 '18 at 1:56
  • 1
    @paxdiablo It does not matter, I am just asking out of curiosity, since all other programming/scripting languages that I know of (for example: Java, C++, JavaScript, PHP, etc.) have a unique memory representation for each data type, so it's interesting to see a scripting language that only have one memory representation for all data types. – user268325 Jan 2 '18 at 10:18
15

Bash variables are untyped.

Unlike many other programming languages, Bash does not segregate its variables by "type." Essentially, Bash variables are character strings, but, depending on context, Bash permits arithmetic operations and comparisons on variables. The determining factor is whether the value of a variable contains only digits.

As another answer says, there is kind of weak form of typing with declare.

This is a very weak form of the typing [1] available in certain programming languages.

See an example:

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.

References:

13

Bash essentially has plain scalar variables, arrays, and associative arrays. In addition, scalars can be tagged as integers with the declare builtin. From the script programmer's / shell user's point of view, string variables act as strings, integer variables act as integers, and arrays accordingly to their type. The internal implementation is not very relevant.


But, if we wish to know how the data is actually stored in memory, we must examine the source code to see what the program actually does.

In Bash 4.4, scalars are stored as strings, regardless of the integer tag. This is visible in the definition of struct variable/ the SHELL_VAR typedef and in the function make_variable_value, which explicitly translates integers to strings for storage.

Arrays are stored in what looks to be a linked list (array.h), and associative arrays as hash tables. The values within them are again stored as strings. The choice of a linked list for arrays may seem odd, but as the arrays can be sparse, and the indexes can be arbitrary numbers regardless of how few elements the array contains, that design choice is a bit easier to understand.

However, the code also contains a definition for the unused union _value, with fields for integer numbers, floating point numbers, as well as string values. It's marked in a comment as "for the future", so it's possible that some future version of Bash will store different types of scalars in their native forms.

1

For the life of me I cannot find this stated anywhere in so many words but this is how I understand it.

Bash is an interpreter, not a compiler and represents all variables as strings. Hence all of the effort and emphasis that goes with the expansions of various kinds.

Bash passes passes all named variables to declare as strings with attributes that control how that variable is to be expanded by declare on storage.

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" )

And of course

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

The coda to this is that even if declare has an internal representation that changes with the attribute flags, strings are all that bash sees or wants to see.

0

This page has a comprehensive guide on typing variables in Bash. This section has more information on the declare built-in command. This code snippet from that link may be of interest:

[bob in ~] declare -i VARIABLE=12

[bob in ~] VARIABLE=string

[bob in ~] echo $VARIABLE
0

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

Here is the man page for declare.

0

It is irrelevant.

The only way to interact with Bash variables is through Bash, so it is impossible for you to notice any difference as to how the variables are stored in memory, because you can never access them through memory directly, you always need to ask Bash for their value, and Bash can then translate them in whatever way it wants to look as if they had been stored in any specific way.

In fact, they may not even be stored in memory at all. I don't know how clever the common implementations of Bash are, but it is at least possible in simple cases to determine whether a variable will be used and/or whether it will be modified, and optimize it away completely or inline it.

  • I think the point of the question was the representation rather than the location – bu5hman Jan 1 '18 at 16:32
  • 2
    My point is that you cannot know the representation, because you cannot observe it. So, it is irrelevant and it might change without you ever noticing. It is simply impossible to tell what representation Bash might choose. You could delve into the sourcecode of an implementation and check out what representation it chooses, but it could change the representation tomorrow in the next patch release and there would be no way for you to know. – Jörg W Mittag Jan 1 '18 at 16:41
  • Schroedingers variables? I do agree with you fundamentally about the underlying representation being irrelevant (see my answer) but in using bash we are effectively 'coding to an interface' and the representation at the interface is stringy. – bu5hman Jan 1 '18 at 16:59
  • 2
    Yes, but the question is not about the representation at the interface boundary, but specifically about how they are "stored in memory". And to that question, I would answer: we don't, can't, and shouldn't know. – Jörg W Mittag Jan 1 '18 at 17:03
  • Which paraphrases the last line of my own post..... as i said, we agree...... and given OPs rep and the nature of the question, I think they will be given reasonable marks for their homework, whoever gets quoted ;-). – bu5hman Jan 1 '18 at 17:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.