Shell Script #5 - Local and Environment Variables
Earlier, we briefly touched on variables. In this article, we will discuss the differences between local and environment variables.
By the end of this article, we want to understand the following screenshot:
The GitHub repository with the code examples: Shell Scripting 101
Local Variables
Local variables, as the name suggests, are variables that are only valid in the shell where they are defined. To see all the variables defined in our shell, we can use the "set" command. Let's take a look at the following example:
[root@localhost ~]# echo $sezisli
[root@localhost ~]# sezisli=ali
[root@localhost ~]# echo $sezisli
ali
[root@localhost ~]# set | grep sezisli
sezisli=ali
[root@localhost ~]# printenv | grep sezisli
[root@localhost ~]# bash
[root@localhost ~]# echo $sezisli
[root@localhost ~]# set | grep sezisli
[root@localhost ~]# env | grep sezisli
Let's examine it line by line:
- We want to print the value of the "sezisli" variable.
- It returns empty.
- We assign the value "ali" to the "sezisli" variable.
- We want to print the value of the "sezisli" variable.
- "ali" is printed.
- We list our variables using "set" and grep for "sezisli".
- The response is sezisli=ali.
- We list our environment variables using "printenv" and grep for "sezisli". No response.
- We open a new shell with "bash".
- We want to print the value of the "sezisli" variable.
- It returns empty.
- We list our variables using "set" and grep for "sezisli". No response.
- We list our environment variables using "printenv" and grep for "sezisli". No response.
"printenv" might be surprising. We'll get to that in a bit. The focus here is on the variable disappearing when we switch to a new shell.
An important point: The variables defined here are only valid in the shell where they were defined. However, they are valid throughout the shell. They are accessible from anywhere inside the shell. For this reason, these variables are also considered "global" rather than "local". If you are seriously looking for "local", let's also take a look at the following topic.
The "local" Keyword
Variables defined with the "local" keyword are only valid within the scope in which they are defined. "local" can only be used inside functions. Let's try to demonstrate this:
#! /bin/bash
#Global değişken:
tarih=1928
ornek_fonksiyon(){
#local anahtar kelimesi, yalnızca fonksiyon içinde kullanılabilir.
#Burada, yine "tarih" isminde bir değişken tanımlıyoruz.
#Sonrasında bu değeri ekrana yazıdırıyoruz:
local tarih=1992
echo "Beni fonksiyon yazdı. tarih=$tarih"
}
echo "Fonksiyon çağrılmadan önce tarih: $tarih"
ornek_fonksiyon
echo "Fonksiyon çağrıldıktan sonra tarih: $tarih"
As seen, even though the value of the "date" variable was set to "1992" inside the function, this value loses its validity once we exit the function.
Environment Variables
In contrast to local variables, variables that are valid in all shells are called "environment variables". In the Bash Configuration Files article, we discussed which files set the default environment variables.
To list all environment variables in your shell, you can use the "env" or "printenv" commands:
[root@localhost ShellScripting101]# printenv
XDG_SESSION_ID=6
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=10.2.2.2 54989 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root/projeler/ShellScripting101
LANG=tr_TR.UTF-8
MODULEPATH=/usr/share/Modules/modulefiles:/etc/modulefiles
LOADEDMODULES=
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
GPG_TTY=/dev/pts/0
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=10.2.2.2 54989 10.2.2.100 22
MODULESHOME=/usr/share/Modules
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
BASH_FUNC_module()=() { eval `/usr/bin/modulecmd bash $*`
}
_=/usr/bin/printenv
OLDPWD=/root/projeler
We see some frequently used variables:
- HOME: The user's home directory.
- HOSTNAME: The device name.
- LANG: Language setting.
- PATH: Directories where executable files are searched.
- USER: User name.
- PWD: The current directory.
- SHELL: The default shell.
- MAIL: The user's mailbox.
export Command
In one of the examples above, we saw that the variable value was lost when the shell was changed. This situation can be prevented. For a defined variable to be valid in subshells, it needs to be "exported".
Subshells can see the variables exported in their parent shell. They can change the values of these variables. However, the changes are only valid in the subshells. In other words, the subshell cannot completely change the variable inherited from the parent shell. Once the subshell terminates, the variable will revert to its original value. Let's examine an example:
#! /bin/bash
#2 adet değişken tanımlıyoruz. Değişken tanımlarken = işaretinin sağ ve sol tarafında boşluk bulunmamalı:
semt=Buca
sehir=İzmir
#Değişkenleri export ediyoruz. Bu sayede bu değişkenler, subshell'ler tarafından da görülebilecektir.
#Aynı anda birden fazla değişkeni export edebiliriz.
#Şöyle de yapabilirdik: export semt=Buca (Atama ve export işlemi aynı anda)
export semt sehir
#Bir değişken daha oluşturuyoruz fakat export etmiyoruz:
test=geldi
#Bu satır, ekrana Buca / İzmir yazacak:
echo $semt / $sehir
#Buraya kadar olan kısım yalnızda export işlemi için. Sonrasında yeni bir shell'e geçin.
#Subshell'de semt ve sehir değişkenlerini görebileceksiniz. Fakat test değişkenini göremeyeceksiniz.
We run the above script without forking a new shell, with a leading "dot" so that the export operation makes sense. For detailed information, you can read The Execution Logic of Shell Scripts:
[root@localhost ShellScripting101]# . ./6-export_ornegi.sh
Buca / İzmir
[root@localhost ShellScripting101]# bash
[root@localhost ShellScripting101]# echo $semt $sehir
Buca İzmir
[root@localhost ShellScripting101]# echo $test
[root@localhost ShellScripting101]# sehir=Ankara
[root@localhost ShellScripting101]# echo $sehir
Ankara
[root@localhost ShellScripting101]# exit
exit
[root@localhost ShellScripting101]# echo $sehir
İzmir
[root@localhost ShellScripting101]# echo $test
geldi
Let's examine line by line:
- We run our script in the current shell.
- It outputs "Buca / İzmir."
- We open a new subshell.
- The values of the "semt" and "sehir" variables, which were exported, are printed. No problem here.
- The "test" variable, which was not exported, returns empty. This is because we haven't defined such a variable in the subshell.
- We update the value of the "sehir" variable to "Ankara" inside the subshell. It correctly prints "Ankara."
- We exit from the subshell (exit).
- The value of the "sehir" variable appears as "İzmir." As mentioned earlier, subshells cannot make permanent changes to variables inherited from their parent.
- The non-exported "test" variable is still accessible in the parent shell.
unset Command
Of course, we also have a command to clean up defined variables. We may want to cancel an exported variable. We might want to clear a defined variable to avoid interfering with the environment's continuity.
As you may recall from the Bash Configuration Files article, the "i" loop variable was used in some configuration files, and at the end of the script, this variable was "unset."

