Bash variables - Things that you probably don't know about it
Updated: Feb 13
Let’s explore the variables scopes and types, the ways to define variables on Bash and when/where to use each one.
About this post
It’s mainly focused on the variable scopes, their differences, when/where to use each of them, etc. I start this post because I see there is a lot of misunderstanding/misuse of the Bash variables. It can be very confusing, complex and I hope this post will help you to know more about the Bash variables, including Bash environment variables. You can check the attributes of the variables using typeset -p.
There are three types of Bash variables: Array, Integer and String. It’s possible to cast/convert the values between all of them, except string to integer (in this case, Bash will set to 0).
The Bash variables are untyped, that means you don’t have to specify types when defining a variable. The default type is string, that means if you don't specify, Bash will consider as a string. For example: im_string=1 It will be a string and not an integer im_array=(array01) It will be an array, because you’re defining it inside of a brackets
On Bash, there are a few ways to define the variables scopes. You can find examples in the "Some ways to get/define the variables" and "Exploring the variables" sections.
This is the most restrictive variable, it’s in a program scope ("a program in a modified environment") and is limited to that program only, once the program ends, the variable will no longer exist. It needs to initiate a sub-process. A program can be a Bash script, an application, etc. It works similar to an environment variable, but only for a sub-process.
This is a variable defined inside of a function. It won’t be accessible between functions nor to the outside of the function. Also, can’t be defined outside of a function.
A global variable can be accessed from the same process. That means, you can define inside/outside of a function and you’ll be able to get from any place of the current, let’s say, script. The global variables won’t be accessible by the sub-processes.
The exported variables are also known as environment variables. It can be accessible by the current process and by the sub-processes. Here is where things get weird, there are two scopes of exported variables. You can have an exported variable in a function scope or in a global scope.
Function scope: It will only be accessible in the function scope and by the sub-processes in that function.
Global scope: It will be accessible inside/outside of the function and can be accessed by the current process and by the sub-processes.
As mentioned above, environment variables and exported variables are the same things.
Some ways to get/define the variables
There are many ways to define/get the variables on Bash, these are just a few of them.
Is a shell builtin command. The declare can define the types and scopes.
var_shortcut="value" => It’s equivalent to declare var_not_shortcut="value"
declare -x exported_var_func_scope="value"=> Define an exported variable in a function scope
declare -g global_var="I am global" => Define a variable in the global scope. It's the same as declare global_var="I am global" or just global_var="I am global" declare global_var="I am global" Will be considered as a local variable if defined inside of a function.
declare -p => Shows all the variables
declare -pi => Shows only the integer variables
declare -a my_array="('value01' 'value02')" => Define an array within two values
declare -l to_lowercase="VALUE" => Define a variable and change to lowercase
Is a command and available via coreutils package. It can only define environment variables in program scope (“a program in a modified environment”)
env => Prints the environment variables for the current process
env my_stricted_var="mslawson" ./initiate_project_pegasus.sh => It will define an exported variable and it will unset once the script is done
Is a shell builtin command. It only defines exported global variables.
export => Prints the exported variables
export exported_var="value" => Define an exported variable
Is a shell builtin command. It only defines local variables inside of a function.
local => Prints the local variables defined in the current function
local my_local_var="value" => Define a local variable. It must be inside of a function
Is a shell built-in command, it's a synonym for declare. It can "set/get attributes and values for shell variables and functions". The typeset -p also includes other variables that aren’t printed via declare (if not used with -p), env, etc. Some of these "extra" variables are BASHPID, BASH_SUBSHELL, RANDOM, SECONDS, etc.
typeset -f => Prints all the functions
typeset -p => Prints all the variables
typeset -x exp_var_func_scope="value" =>It defines an exported variable in a function scope.
Get variables from a file
On Linux/Unix, everything is a file, right? This wouldn't be different for the environment variables. There are “three” files under the /proc that you can get these variable. These files are /proc/<PID>/environ, /proc/self/environ and /proc/thread-self/environ.
Exploring the variables
Now we know a little bit more about the variables on Linux. Let’s go to the last part of this blog, let’s explore the "map" and see some practical examples.
Variables outside the function
In this simple example, I’m showing the difference between each variable and the commands used to define them. I’m only defining variables outside of a function, then trying to read from inside and outside of a function.
You’ll see that there are not many differences in this case. This is because the variables are defined in the scripts and by default, the functions inherit all the variables.
Variables inside the function
Now it’s when the things start looking different. In this example, just two of the variables can be accessed from outside of the function. This is because one of them is a global variable and the other one is an exported global variable.
Just a reminder, the global variable can be accessed from anything in that script, but not by the sub-processes. The exported global variables means that it can be accessed by anything in that script and by the sub-processes too.
These are the versions used to write this post
CentOS Linux release 7.9.2009 (Docker container centos:7)