Shell scripting fundamentals

Shell scripting fundamentals

Bash | Variables | Command line arguments | Inputs | Arithmetics operations

Versión en español: Fundamentos de shell scripting


Shell scripts are designed for execution by Unix Shell and are typically used to automate repetitive tasks or to perform a series of complex tasks through Shell commands.

See a shell example script below:

#!/bin/bash

# Script example
echo "Hello World!"
  • #: The "shebang" line specifies the interpreter to be used, in this case, bash.

  • Every comment should begin with a "#" character.

  • Upon executing the program, the console will display "Hello World!" on the screen.

A common way to execute a shell script will look like this:

./hello_world.sh

It's very important to assign the proper execution permissions to the file through the following command chmod +x hello_world.sh

Variables

Naming variables in the shell are ruled by the following:

  • They must start with a letter or an underscore.

  • Numbers are allowed in any other position.

  • They cannot contain special characters like @, #, %, and $.

  • They are upper and lower-case sensitive ( var != VAR ).

  • Allowed variables : VARIABLE, VAR123, var_name, _var

  • Not allowed variables: 1var, %var, var-name

To refer to a variable we have to set the "$" sign before the name of the variable ( $PATH, $my_var ).

A good practice is

Names of local variables must be written in lowercase and separated by an underscore ( my_var ).

There are 2 types of variables

  • Global variables (environment):

    • Provide a simpler way to share configurations between multiple programs.

    • Usually, it uses just capital letters in its name by convention ( PATH, PWD ).

    • Will be listed by executing the printenv or env command.

    • Are inherited by the subshells.

    • To declare them you must set the word export before the variable ( export name=value ).

  • Local variables:

    • Are available just for the shell where were created.

    • Are not inherited by the subshells.

A subshell is a child process started by the shell or a shell script.

  • Executing a shell script always starts a new subshell and it executes on it.

  • A subshell can be started by executing the bash command from an interactive shell.

Variable inheritance

A declared global variable in the shell will be accessible in a subshell started from the initial shell, while a declared global variable declared in a subshell will not be accessible in the initial shell.

> export VAR1=value
> bash
> echo $VAR1
value
> var1=value
> bash
> echo $var1
# -- no value exists in the subshell --
> bash
> export VAR1=value
> echo $VAR1
value
> exit
> echo $VAR1
# -- no value exists in the shell --

Command line arguments

It's possible to pass values to the scripts at the time they're going to be executed through the command line as shown in the following example:

#!/bin/bash

text_to_print=$1
echo $text_to_print
> ./hello_world.sh 'Hello World!'
Hello World!

When executing a script, the entered command is divided into multiple parts and each part is stored in embedded variables starting with the number 0, the command itself will be available in the variable called $0 and the second part of the command (the value we wanted to pass to the script) is stored in the variable $1, in case of having more parts in the command, these will be storage in $2, $3, $4, etc.

A good practice is

Passing arguments to set the necessary values of the variables defined in the script helps to ensure that they could be reused and don't need to be edited each time before executing them.

Inputs

Another way to pass variables to a script is to request it from the user once the script is executed, instead of passing it through the command line as in the following example:

#!/bin/bash

read -p "Enter the text to print: " text_to_print
echo $text_to_print
> ./hello_world.sh
Enter the text to print: Hello World!
Hello World!

When using the read command followed by the variable name, when the script executes and reaches that instruction, it will wait for the user to enter a value, once this happens that value will be stored in the indicated variable.

We can add, to the read command, the flag -p just before the name of the variable to specify a message to the assign value request.

Command line arguments vs Inputs

Both types of variable assignment allow the script to be reused without the needing of modifying it before using it, but each of these options must be used in different situations.

  • Command Line Arguments

    • Scripts are called by other scripts.

    • Scripts that don't need manual intervention.

  • Inputs

    • For simple scripts that are used independently.

    • Scripts that require approval (before deleting a file, making important changes on the system, etc).

Both options can be used in a single script, but every time an input exists, a manual intervention must be required to complete the execution of the script.

Arithmetic operations

There are different ways to perform arithmetic operations in the shell, one of them is using the expr command as shown in the following example:

> expr 2 + 3
5

Entering an arithmetic expression as input for the expr command will produce the result as output.

The operator ( +, -, *, /, **, % ) must be separated from the values by a space.

In the case of multiplication, the operator must carry the scape symbol \* (because the asterisk symbol is a reserved shell-reject character).

Arithmetic operations can also be performed with variables as shown in the following example:

> A=2
> B=3
> expr $A + $B
5

Another way to perform arithmetic operations in bash is using double parentheses, this way is more similar to how it would be performed in another programming language, this way the expression is encapsulated inside the double parentheses with the $ symbol as a prefix as shown in the following example:

> echo $((2 + 3))
5
> A=2
> B=3
> echo $((A*B))
6

When using double parentheses the following consideration should be taken into account:

  • It is not necessary to keep the space between the operator and the values/variables.

  • It is not necessary to use the scape symbol \ with the operator *.

  • It is not necessary to place the symbol $ as a prefix for each variable, one before the parentheses is sufficient.

Both expr and double parentheses only return an integer as output in a division when the input are integers, but for this you can use the utility called bc (it works like a basic calculator in Linux) with the option -l to generate the results with decimals as you can see in the following example:

> echo $((10 / 3))
3
> echo 10 / 3 | bc -l
3.33

bc works in interactive mode by default, where only the expression is entered and it generates the result, but it is posibble to use it together with the command echo and the pipe character | to not enter the interactive mode and get the result directly.


If you found it helpul, like/share this article so it reaches others and if you're new in the blog, we'd appreciate it if you follow us! We try to write articles to keep track of everything we've learned or personally want to read, what we love to know and how we did it or get ideas from readers.

See you back soon!