7 ‐ Shell Scripting - CloudScope/DevOpsWithCloudScope GitHub Wiki

What is a Shell Script ?

  • A shell script is a file containing a series of commands that the shell (command-line interpreter) executes. It allows you to automate repetitive tasks, manage system operations, and handle complex workflows.

Creating a Shell Script

To create a shell script:

  • Open a text editor (like nano, vi, or gedit).

  • Write your commands.

  • Save the file with a .sh extension (e.g., myscript.sh).

Basic Syntax

  • Shebang: The first line of a shell script is usually a shebang (#!) followed by the path to the shell.

  • For example, #!/bin/bash specifies that the script should be run with the Bash shell.

#!/bin/bash

echo "Hello, World!"

  • Comments: Comments begin with #. They are ignored by the shell. #

  • variables: Variables are used to store data. Define a variable by assigning a value without spaces around the = sign.

name="John"

echo "Hello, $name!"

  • Commands: Commands are executed in sequence. You can use built-in commands like echo, ls, cd, and mkdir.

echo "Listing files:"

ls

  • Control Structures: Shell scripts support conditional statements and loops.

    • Conditional Statements (if)

      if [ "$name" == "John" ]; then
      
           echo "Hello, John!"
      
      else
      
          echo "Hello, stranger!"
      
      if
      
  • Loops (for, while):

for i in 1 2 3; do

    echo "Number $i"

done


count=1

while [ $count -le 3 ]; do

    echo "Count $count"

    count=$((count + 1))

done

Making a Script Executable

After creating the script, you need to make it executable. Use the chmod command:

chmod +x myscript.sh

Run the script with:

./myscript.sh

Basic Commands in Shell Scripts

echo: Outputs text to the terminal.

read: Reads input from the user.

cp, mv, rm: Copy, move, and remove files, respectively.

grep: Searches for patterns in files.

awk, sed: Text processing tools.

$?: last command execution result

0: success

1: General error

130: Terminated by ctrl + c

127: Command not found

Using Functions

You can define functions in a shell script to organize and reuse code.

my_function() {

   echo "This is a function"

}

my_function

Error Handling

Use exit to end the script with a status code, and trap to handle errors or cleanup.

trap 'echo "An error occurred. Exiting..."; exit 1;' ERR

Debugging

Use -x option to debug scripts, which prints each command before executing it.

bash -x myscript.sh

Variables

  1. Global Variables

Definition: Global variables are variables that are accessible throughout the entire script. Once a global variable is defined, it can be used anywhere within the script.

Usage: Global variables are useful when you need to share data between different parts of the script or across functions.

#!/bin/bash

# Define a global variable

global_var="I am global"

# Function that uses the global variable

function print_global() {
    echo $global_var
}

print_global  # Output: I am global
  1. Local Variables

Definition: Local variables are variables that are confined to the scope of a function. They are not accessible outside the function in which they are defined.

Usage: Local variables are useful for keeping function-specific data and avoiding unintended interactions with global variables.

#!/bin/bash

# Define a global variable

global_var="I am global"

# Function that uses a local variable

function my_function() {

    local local_var="I am local"

    echo $local_var

    echo $global_var  # Accessing global variable inside function

}

my_function  # Output: I am local

echo $local_var  # Output: (nothing, as local_var is not accessible outside the function)

echo $global_var  # Output: I am global
  1. Environment Variables

Definition: Environment variables are global variables that are available to all processes running in the shell session. They are typically used to pass configuration data to programs and scripts.

Usage: Environment variables can be used to configure system settings, specify paths, and more. They are set and exported so that they are inherited by subprocesses and child processes.

#!/bin/bash

# Set an environment variable

export MY_ENV_VAR="I am an environment variable"

# Function that uses the environment variable

function print_env_var() {

    echo $MY_ENV_VAR

}

print_env_var  # Output: I am an environment variable

Summary of Key Differences

  • Global Variables: Accessible throughout the script, including all functions.

  • Local Variables: Restricted to the function where they are defined; not accessible outside that function.

  • Environment Variables: Available to all processes in the shell session and its child processes. Defined with export to ensure they are available outside the current shell.

Array Elements

In Bash, @ is used with arrays to represent all elements of the array. It is often used with double quotes to handle elements that contain spaces.

#!/bin/bash

# Define an array

my_array=("one" "two" "three")

# Print all elements of the array

echo "All elements of the array:"

for item in "${my_array[@]}"; do

    echo "$item"

done

In this script, ${my_array[@]} is used to access all elements of my_array.

Quoting "${my_array[@]}" ensures that each element is treated as a separate item, preserving spaces within elements.

Positional Parameters

The @ symbol is also used to refer to all positional parameters in a script. Positional parameters are the arguments passed to a script or function.

#!/bin/bash

# Print all positional parameters

echo "All positional parameters:"

for param in "$@"; do

    echo "$param"

done

When you run this script with arguments, for example ./script.sh arg1 arg2 arg3, the output will be:

All positional parameters:

arg1

arg2

arg3

Array Indices

In Zsh, @ is used similarly to how it's used in Bash for arrays, but it can also be used to manipulate array indices.

#!/bin/zsh

# Define an array

my_array=("apple" "banana" "cherry")

# Print all elements of the array

echo "All elements of the array:"

for item in ${my_array[@]}; do

    echo "$item"

done

In this Zsh example, ${my_array[@]} accesses all elements of my_array.

tee Command

Usage: command | tee [options] file

Function: Reads from standard input and writes to both standard output and the specified file. Useful for logging output while still displaying it on the terminal.

Options:

-a: Append to the file instead of overwriting.

-i: Ignore the interrupt signals.

echo "Log this line" | tee log.txt

echo "Another log entry" | tee -a log.txt

> (Redirection with File Descriptor Manipulation)

  • Usage: command > file 2>&1

  • Function: Redirects both stdout and stderr to the same file. 2>&1 means redirect stderr (2) to the same place as stdout (1).

    ls /some_directory > output.log 2>&1
    
  • Usage: command > file

  • Function: Redirects the standard output (stdout) of command to file. If file already exists, it will be overwritten.

    echo "Hello, World!" > output.txt
    

2> (Standard Error Redirection)

Usage: command 2> file

Function: Redirects the standard error (stderr) of command to file. If file already exists, it will be overwritten.

ls non_existent_file 2> error.log

2>> (Append Standard Error)

Usage: command 2>> file

Function: Appends the standard error of command to file. If file does not exist, it will be created.

ls another_non_existent_file 2>> error.log

>> (Append Standard Output)

Usage: command >> file

Function: Appends the standard output of command to file. If file does not exist, it will be created.

echo "Another line" >> output.txt

File system flag usages

When working with shell scripts, especially in Bash, it's common to use conditional statements (if-else) with file system flags to check the properties of files and directories. Below are some common flags and how they are used in if-else conditions:

Common File Flags in Bash:

  1. -d: Checks if the specified path is a directory.

    if [ -d "/path/to/directory" ]; then
        echo "It's a directory"
    else
        echo "It's not a directory"
    fi
    
  2. -f: Checks if the specified path is a regular file.

    if [ -f "/path/to/file" ]; then
        echo "It's a file"
    else
        echo "It's not a file"
    fi
    
  3. -e: Checks if the file or directory exists.

    if [ -e "/path/to/item" ]; then
        echo "It exists"
    else
        echo "It does not exist"
    fi
    
  4. -r: Checks if the file or directory is readable.

    if [ -r "/path/to/file" ]; then
        echo "It's readable"
    else
        echo "It's not readable"
    fi
    
  5. -w: Checks if the file or directory is writable.

    if [ -w "/path/to/file" ]; then
        echo "It's writable"
    else
        echo "It's not writable"
    fi
    
  6. -x: Checks if the file or directory is executable.

    if [ -x "/path/to/file" ]; then
        echo "It's executable"
    else
        echo "It's not executable"
    fi
    
  7. -s: Checks if the file is not empty (size greater than zero).

    if [ -s "/path/to/file" ]; then
        echo "File is not empty"
    else
        echo "File is empty"
    fi
    
  8. -L: Checks if the specified path is a symbolic link.

    if [ -L "/path/to/link" ]; then
        echo "It's a symbolic link"
    else
        echo "It's not a symbolic link"
    fi
    

Example with if-else Conditions:

Here's an example script that uses multiple flags in an if-else condition:

#!/bin/bash

FILE="/path/to/some/file"

if [ -e "$FILE" ]; then
    if [ -d "$FILE" ]; then
        echo "$FILE is a directory."
    elif [ -f "$FILE" ]; then
        echo "$FILE is a file."
        
        if [ -r "$FILE" ]; then
            echo "It is readable."
        fi
        
        if [ -w "$FILE" ]; then
            echo "It is writable."
        fi
        
        if [ -x "$FILE" ]; then
            echo "It is executable."
        fi
    elif [ -L "$FILE" ]; then
        echo "$FILE is a symbolic link."
    else
        echo "$FILE exists but is neither a file nor a directory."
    fi
else
    echo "$FILE does not exist."
fi

Tips:

  • Use && and || for combining conditions within an if statement.
  • Quoting variables is important to handle paths with spaces or special characters.
  • Check permissions and ownerships with -r, -w, and -x to ensure that operations are safe and authorized.

These flags and examples help you control and manage your scripts by making decisions based on the characteristics of files and directories in the file system.