Bash Scripting for n00bz

## What are this??

### Bash

Bash is a command language interpreter which is widely used on various operating systems, and is the default command interpreter on most GNU/Linux systems. The name stands for **B**ourne-**A**gain **SH**ell.

### Shell

Shell is a macro processor which allows for interactive or non-interactive command execution.

### Scripting

Scripting allows for commands to be automatically executed that would otherwise be executed manually one-by-one.

## Basic knowledge

### What is shell

The terminal window contains shell, and shell allows you to use commands that interact with the computer. Tasks like storeing data, processing information, and various other simple or even complex tasks.

Examples of these commands: *date*, *cal*, *pwd*, or *ls* followed by the enter key.

### What is scripting

When running these individual tasks becomes tedious and you want to be able to execute a bunch of commands together, that's when scripting comes in.

For example, we could write a script with the above example commands like so:

*task.sh*

```
#!/bin/bash

date
cal
pwd
ls

```

Once you have written this, we can make the file executable using the *chomd* *-x* command. Now your script can be run by typing *./task.sh*

With scripting, any shell command can be automated.

We can also automatically execute shell scripts daily at any time by using cron time-based job scheduler and store the script's output to a file every time it is executed.

### What is Bash?

Bash is the default interpreter on many GNU/Linux systems, so we could have run task.sh without the initial shebang command. However is it good practice to define the shell interpreter to be used explicitly like we did above.

Because there are various other shell interpreters out there, such as Korn shell and C shell. To see what your default interpreter is simply run:

```
echo $SHELL

```

To define your script's interpreter as Bash, first we must locate a full path to its executable binary using the *which* command. Then prefix with a shebang (*#!*) and insert it as the first line of your script (like we did in the 'task.sh' example.

### File names and permissions

In order to run a script as an executable you need to run *chmod -x <filename>* cammand. By default, any newly created files are not executable regardless of its file extension.

In fact, the file extension on GNU/Linux systems mostly doesn't mean anything apart from the fact that upon execution of the *ls* command it is immediatley clear that the file with the extension *.sh* is a shell script, and a file with *.jpg* is a lossy compressed image.

You can use the *file* command to identify the type of a file.

### Script Execution

In the previous example we define how the script is interpreted by defining the shebang at the beginning of the script.

Another way we can execute scripts is by calling the bash interpreter explicitly:

```
user@user ~ $ bash script.sh

```

Doing this means we don't need to define the shebang in the script because we are calling the bash executable binary explicitly, so the content of the script is loaded and interpreted as bash shell script.

### Relative vs Absolute path

GNU/Linux offers a simple compass tool to help navigate through your filesystem with the command *pwd*. When executed will always print your current location.

An **absolute path** is the location of a file or directory from the root directory.

A **relative path** is defined as the path related to your present working directory (*pwd*)

## Basic shell script examples

### Simple 'Hello World' script.

```
#!/bin/bash

echo "Hello World"

```

### Basic backup shell script

This next script can be used to backup our user home directory.

To do this we will be using the *tar* command with options *-czf* in order to create a compressed tar ball of the entire home directory.

```
#!/bin/bash

tar -czf /tmp/myHome_directory.tar.gz /home/linuxconfig

```

*c* - Create a new archive

*z* - Filter the archive through gzip

*f* - Use archive file or device archive

### Example using variables

```
#!/bin/bash

# Variables.
greeting="Welcome"
user=$(whoami)
day=$(date +%A)

echo "$greeting back $user! Today is $day, which is the best day of the entire week!"
echo "Your Bash shell version is: $BASH_VERSION. Enjoy!"

# $BASH_VERSION is an internal variable defined as part of your shell.

```

Using variables we can enhance our backup script to prodice a more meanigful output file name by incorporating a date and time when the backup on our home directory was successfully performed. As well as allowing the script to detect the current user who is running the script.

```
#!/bin/bash

# Script used to backup a user's home directory to /tmp/.

user=$(whoami)
input=/home/$user
output=/tmp/${user}_home_$(date + %Y-%m-#d_%H%M%S).tar.gz

tar -czf $output $input
echo "Backup of $input completed! Details about the output backup file:"
ls -l $output

```

This script introduces yes another concept *${parameter}* which is called **parameter expansion**.

In our case, curly braces *{}* are required because our variable *$user* is followed by characters which are not part of its variable name.

#### Parameter Expansion

The basic form of parameter expansion is *${parameter}*. The value of *parameter* is substituted. The *parameter* is a shell parameter or an array reference. The braces are required when *parameter* is a positional parameter with more that on digit, or when *parameter* is followed by a character that is not to be interpreted as part of its name.

### Input, Output and Error Redirections

Normally commands executed on GNU/Linux command line either produce output, require input or throw an error message. This is a fundemental concept for shell scripting as well as for working with GNU/Linux's commands in general.

Executing a command will result in one of the three following outcomes:

1. The command will produce an expected ouput.
2. The command will generate an error.
3. The command might not produce any output at all.

Let's say for example we are trying to run the command *ls -l foobar* when we do not have a file called 'foobar'.

If we run this it will produce a **standard error output (stderr)**. But if we have a file called 'foobar' we will produce **standard output (stdout)**.

The difference between **stdout** and **stderr** output is important as it allows up to a redirect output separately.

the *>* notation is used to redirect **stdout** to a file and *2>* notation is used to redirect **stderr** and *&>* is used to redirect both **stdout** and **stderr**.

Now we can adjust our script again to eliminate any unwanted **stderr** message by redirecting it with *2>* notation to */dev/null*. Think of /dev/nullas a data sink which discards any data redirected to it.

```
#!/bin/bash

user=$(whoami)
input=/home/$user
output=/tmp/${user}_home_$(date +%Y-%m-%d_%H%M%S).tar.gz

# Send stderr output to the trash.
tar -czf $output $input 2> /dev/null
echo "Backup of $input completed! Details about the output backupfile:"
ls -l $output

```

*script WITHOUT stderr handling:*

```
$ ./backup.sh
**tar: Removing leading `/' from member names**
Backup of /home/linuxconfig completed! Details about the output backup file:
-rw-r--r-- 1 linuxconfig linuxconfig 8778 Jul 27 12:30 /tmp/linuxconfig_home_2017-07-27_123043.tar.gz

```

*script WITH stderr handling:*

```
$ ./backup.sh
Backup of /home/linuxconfig completed! Details about the output backup file:
-rw-r--r-- 1 linuxconfig linuxconfig 8778 Jul 27 12:30 /tmp/linuxconfig_home_2017-07-27_123043.tar.gz

```

See that the *tar: Removing leading `/' from member names* doesn't get printed anymore, because it is sent to **stderr** descriptor and now will get sent to */dev/null*.

Another descriptor bash shell also has is an input descriptor called **stdin**. Generally terminal input comes from a keyboard. Any keystroke you type is accpeted by **stdin**.

The alternative method is to accept command input from a file using *<* notation. Say we were to feed *cat* command from the keyboard and redirect the output to *file1.txt*.

```
echo "testing..." > testFile.txt

```

If you run a *cat* command on *testFile.txt* you will get *testing...* printed out.

You can also accept command input from a file using the *<* notation. Say we were feeding a *cat* command and redirecting the output