Bash Environment

Environment Variables

Local Variables

Not available to child processes by default.

# setting a local variable
a=apples

# setting multiple local variables in one statement
b=berries c=carrots
d=dogs; e=elephants

echo $a $b $c $d $e

# None of the variables above are inherited by child processes
bash -c 'echo $a $b $c $d $e'

Setting, Unsetting and Testing

Variables can be set and unset within a shell session, and tested for conditional logic

# From a new shell
test ! $a && echo 'variable a does not exit'

# Setting and testing the variable
a=apples
test $a && echo 'variable "a" now exists'

# unsetting and testing the variable, we don't include thr $
unset a
test ! $a && echo 'Once again variable "a" does not exit'

Exporting Variables to child processes

To make a variable or a set of variables available to subshells (or sub processes), they need to be exported.

# before exporting
a=apricot
bash -c 'test ! $a && echo variable "a" not set in the subprocess'

# after exporting
export a
bash -c 'echo $a'

# the variable needs to be exported once, changing the value doesn't require re-exporting
a=apples
bash -c 'echo $a'

# to un-export the variable
export -n a
bash -c 'test ! $a && echo variable "a" not set in the subprocess'

Exporting Variables Automatically

To export variables using the export command explicitly, the set -a option can be used

set -a
# these two variables are exported automatically
a=apples
b=berries

set +a
# these two variables are NOT exported automatically
c=carrots
d=durian

bash -c 'echo $a $b $c $d'

Exporting Variables From a file

set -a useful when souring environment variables from a .env file. This is the best way to export variables from a file, especially when some lines in the file are # commented, or contains other shell logic

# creating a file with 4 variable assignments
echo 'a=apples' >> fruits.env
echo 'b=berries' >> fruits.env
echo 'c=carrots' >> fruits.env
echo 'd=durian' >> fruits.env

set -a
# load the variables from the .env file
source fruits.env
rm fruits.env
set +a

bash -c 'echo $a $b $c $d'

Passing Variables to Subprocess without exporting

If it is desirable to pass variables that shouldn’t be set in the parent, variables can be set (without exporting) before executing the subprocess.

# Variables Set and passed to subprocess
a=apples b=berries bash -c 'echo $a $b'

# Variables are not set in the parent (current) Shell
echo $a $b

Shell Expansions

https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html

Brace Expansion

Brace expansion is a mechanism by which arbitrary strings may be generated

# sequence expression over ASCII
echo ``letter_{a..z}``

# sequence expression over integers
echo ``number_{1..24}``

# sequence expression with an increment setting
echo ``number_{1..24,2}``

echo ``software_{alpha,beta,gamma}``

Variable Expansions

Many more expansion forms on. Mostly to match on variable names. https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

${parameter:-word}

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

echo ${PING:-SHELL} # PONG

echo ${PING2:-SHELL} # SHELL

echo ${PING2:-$SHELL} # /bin/bash
${parameter:=word}

If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

${parameter:?word}

If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

${parameter:+word}

If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

${parameter:offset} and ${parameter:offset:length}

Substring of the parameter

# We gotta use the braces in this context
prefix=super
echo ${prefix}man and ${prefix}woman

# Treat unset variables as an error
set -u

echo $prefix2

echo "last exit status: $?"

name=postgresql
# cut the last two characters
echo ${name:0:-2}

Command Substitution

$() string substitution of the std out of a command. is nestable in “” and within other expansions

cd $(pwd)
echo "pulse" > file_$(date +%s).log

# latest Distro Kernel
latest_kernel=$(ls /lib/modules -At | head -n 1)

Arithmatic Substitution

# arithmatic in the shell
v=$(( 4 - 3 )); echo $v

# inside a double-quote string
echo "4 - 3 is $(( 4 - 3 ))"

# inside a command expansion
echo $(echo $(( 4 - 3 )))

# inside all sort of Expansion and substitution expressions
array=( a b c d )
echo "last element is ${array[$(( ${#array[@]} - 1 ))]}"