/bash-intro-tutorial

This repositoy contains all the code we used in the Youtube bash tutorial

Primary LanguageShell

BASH Notes

Introduction


What is BASH?

  • A shell language
  • Short for Bourne Again Shell
  • Easy Commands.

Why learn BASH?

  • Most used and popular shell language.
  • Used since early days of linux
  • Comes with Linux and other OS(MAC, windows using WSL)

Why not BASH?

  • Lacks features needed for Advance scripts
  • No OOP
  • Difficult syntax compared to Python
  • Newer tools available like Ansible
  • Advanced script python is preferred.

Still useful

  • Lightweight and always available.
  • Basic knowledge makes big difference.




Understanding BASH script file


#!/bin/bash

#Prompt the user for their name
echo "Please enter your name: "

#Read the user's input into the name variable
read name

#Print a greeting message
echo " Hello , $name!"

Consider the above example

  1. Shebang(#! line): A bash script usually starts with a shebang line at the beginning, which tells the system which interpreter to use to execute the script.

  2. Comment : Use '#'

  3. Variable: Variable names are case sensitive and can contain letters, numbers and underscore in the name.

  4. Command Execution: Commands are typically written one per line and they are executed sequentially from top to bottom.

  5. Control Structure: Conditional(if-else-then), loops(for,while,until) and case.





Positional Arguments

  1. $0: Represents the name of the script or command shell
  2. $1: first positional argument
  3. $2: second positional argument . . . $n: nth positional argument

Example the script below:

#!/bin/bash

# Check if at least two positional arguments are provided
if [ $# -ge 2 ]; then
    echo "The first argument is: $1"
    echo "The second argument is: $2"
else
    echo "Usage: $0 <arg1> <arg2>"
fi

The script is called in below format

./test.sh arg1 arg2




Output/Input redirection in shell


Output redirection in shell scripting allows you to change the destination of the output generated by a command or script. By default, the output of a command is usually displayed in the terminal (standard output, often denoted as `stdout`). However, you can use redirection operators to send the output to a file or to another command's input. Here are some common output redirection operators in shell scripting:
  1. > (Greater Than Symbol): This operator redirects standard output to a file. If the file does not exist, it is created; if it exists, it is overwritten. For example:

    command > output.txt
  2. >> (Double Greater Than Symbol): This operator appends standard output to a file. If the file does not exist, it is created; if it exists, the output is added to the end of the file. For example:

    command >> output.txt
  3. 2> (Greater Than Symbol Followed by 2): This operator redirects standard error (stderr) to a file. For example:

    command 2> error.txt
  4. 2>> (Double Greater Than Symbol Followed by 2): This operator appends standard error (stderr) to a file. For example:

    command 2>> error.txt
  5. &> or &>>: These operators redirect both standard output and standard error to a file. For example:

    command &> output_and_error.txt
  6. < (Less Than Symbol): This operator is used for input redirection, allowing you to read data from a file as input for a command. For example:

    command < input.txt
  7. << (Double Less than symbol): Allows you to create a here document, which is a way to provide input to a command within your script. The content between << EOF and EOF is treated as input to the command. This is particularly useful when you want to provide multiple lines of input or specify configuration settings. For example:

    # Use a here document to provide input to 'cat'
    cat << EOF
    This is line 1
    This is line 2
    EOF
  8. | (Pipe Symbol): This operator is used for piping the output of one command as input to another command. It doesn't create files but is a way to pass data between commands. For example:

    command1 | command2

Here are some examples of how to use output redirection:

  • Redirect standard output to a file:

    echo "Hello, World!" > output.txt
  • Redirect standard error to a file:

    command_that_generates_error 2> error.txt
  • Redirect both standard output and standard error to a file:

    command &> output_and_error.txt
  • Append standard output to an existing file:

    echo "This is additional text." >> existing_file.txt
  • Pipe the output of one command as input to another:

    cat input.txt | grep "pattern"

Output redirection is a powerful feature in shell scripting that allows you to control where the output of commands goes, making it useful for logging, capturing results, and processing data.

Input redirection allows you to automate tasks by providing data to commands or scripts without manual user input. It's a valuable feature for processing files, configuration, and other data sources within shell scripts.





Test Operators in shell


In shell scripting, test operators are used to evaluate conditions and return a Boolean result (true or false) based on the outcome of the test. The `test` command, often used with square brackets `[ ]`, is commonly used for conditional checks within shell scripts. Alternatively, you can use the `[[ ]]` construct in Bash for more advanced and flexible tests. Here are some commonly used test operators:
  1. Numeric Comparisons:

    • -eq: Equal to (e.g., [ "$a" -eq "$b" ] checks if $a is equal to $b).
    • -ne: Not equal to (e.g., [ "$a" -ne "$b" ] checks if $a is not equal to $b).
    • -lt: Less than (e.g., [ "$a" -lt "$b" ] checks if $a is less than $b).
    • -le: Less than or equal to (e.g., [ "$a" -le "$b" ] checks if $a is less than or equal to $b).
    • -gt: Greater than (e.g., [ "$a" -gt "$b" ] checks if $a is greater than $b).
    • -ge: Greater than or equal to (e.g., [ "$a" -ge "$b" ] checks if $a is greater than or equal to $b).
  2. String Comparisons:

    • =: Equal to (e.g., [ "$str1" = "$str2" ] checks if $str1 is equal to $str2).
    • !=: Not equal to (e.g., [ "$str1" != "$str2" ] checks if $str1 is not equal to $str2).
  3. File Tests:

    • -e: Checks if a file exists (e.g., [ -e "$filename" ]).
    • -f: Checks if a file exists and is a regular file (not a directory or a special file).
    • -d: Checks if a directory exists.
    • -s: Checks if a file is not empty (size greater than zero).
    • -r, -w, -x: Checks if a file is readable, writable, or executable, respectively.
  4. Logical Operators:

    • !: Negation (e.g., [ ! -e "$filename" ] checks if the file does not exist).
    • -a: Logical AND (e.g., [ "$a" -eq 1 -a "$b" -eq 2 ] checks if both conditions are true).
    • -o: Logical OR (e.g., [ "$a" -eq 1 -o "$b" -eq 2 ] checks if at least one condition is true).
  5. String Tests:

    • -z: Checks if a string is empty (e.g., [ -z "$str" ]).
    • -n: Checks if a string is not empty (e.g., [ -n "$str" ]).
  6. File Comparisons:

    • file1 -nt file2: Checks if file1 is newer than file2.
    • file1 -ot file2: Checks if file1 is older than file2.

These operators can be used in conditional statements such as if, elif, and while to perform tests and make decisions within shell scripts. For example:

if [ "$a" -eq 10 ]; then
    echo "The value of 'a' is 10."
fi

if [ -e "$filename" ]; then
    echo "The file exists."
else
    echo "The file does not exist."
fi

Keep in mind that you can also use the [[ ]] construct in Bash for more advanced and flexible conditional tests, which provide additional capabilities, such as pattern matching and logical operators.



If/Elif/Else


The `if`, `elif` (short for "else if"), and `else` statements are used in shell scripting and various programming languages to control the flow of a program based on conditional tests. They allow you to execute different blocks of code depending on whether certain conditions are true or false. Here's the basic syntax for using `if`, `elif`, and `else` statements in shell scripts:

if condition1; then
    # Code to execute if condition1 is true
elif condition2; then
    # Code to execute if condition1 is false and condition2 is true
else
    # Code to execute if neither condition1 nor condition2 is true
fi
  • if: The if statement is used to test a condition. If the condition is true, the code block following then is executed.

  • elif: The elif statement is used to test an alternative condition if the previous if condition is false. You can have multiple elif statements to test different conditions sequentially.

  • else: The else statement is optional and is executed if none of the previous conditions (including the if and any elif statements) are true.

Here's an example of how if, elif, and else statements can be used in a shell script:

#!/bin/bash

score=85

if [ "$score" -ge 90 ]; then
    echo "Grade: A"
elif [ "$score" -ge 80 ]; then
    echo "Grade: B"
elif [ "$score" -ge 70 ]; then
    echo "Grade: C"
elif [ "$score" -ge 60 ]; then
    echo "Grade: D"
else
    echo "Grade: F"
fi

In the above script, based on the value of the score variable, it determines the corresponding grade using if, elif, and else statements.

  • If score is greater than or equal to 90, it prints "Grade: A".
  • If score is between 80 and 89, it prints "Grade: B".
  • If score is between 70 and 79, it prints "Grade: C".
  • If score is between 60 and 69, it prints "Grade: D".
  • If score is below 60, it prints "Grade: F".

You can use if, elif, and else statements to handle more complex conditional logic and make decisions within your shell scripts based on various conditions.





Case statements


They are better than if/elif/else when

  • Checking for multiple values
  • is easier to read

In shell scripting, a case statement is used for conditional branching, allowing you to execute different blocks of code based on the value of a variable or an expression. A case statement is particularly useful when you have multiple conditions to check and want a more structured and readable way to handle them.

The basic syntax of a case statement in Bash looks like this:

case expression in
    pattern1)
        # Code to execute if expression matches pattern1
        ;;
    pattern2)
        # Code to execute if expression matches pattern2
        ;;
    ...
    patternN)
        # Code to execute if expression matches patternN
        ;;
    *)
        # Default code to execute if none of the patterns match
        ;;
esac

Here's a breakdown of how a case statement works:

  • case: Begins the case statement.
  • expression: The value or variable you want to evaluate.
  • in: Separates the expression from the patterns.
  • pattern1, pattern2, ..., patternN: Patterns to match against the expression.
  • ) (right parenthesis): Marks the end of each pattern.
  • ;; (double semicolon): Separates each code block associated with a pattern.
  • *): A wildcard pattern that matches anything. It is used as a default case if none of the patterns match.
  • esac: Marks the end of the case statement.

Here's an example of a case statement in a shell script:

#!/bin/bash

fruit="apple"

case "$fruit" in
    "apple")
        echo "It's an apple."
        ;;
    "banana")
        echo "It's a banana."
        ;;
    "orange")
        echo "It's an orange."
        ;;
    *)
        echo "It's something else."
        ;;
esac

In this script, the value of the fruit variable is checked against different patterns, and the corresponding block of code is executed based on the match. In this case, it will print "It's an apple."

You can have as many patterns as needed, and each pattern can contain multiple conditions. Case statements are particularly useful when you have a finite number of options to check, making your code more structured and easier to read than a series of if/elif/else statements for each condition.



Arrays

You can assign multiple values to one variable collected in a list which we call them arrays.

You can create them like this:

VariableName=(value1 value2 value3 value3)
  • VariableName: Name of the array you want.
  • () (brackets): You can use which of (), [], {} but you should remember to use the same opening and closing brackets.
  • (space): Each index of values separated by space.

To call them you should do

${VariableName[index]}
  • VariableName: Name of the array you Initialized.
  • index: The index number you want. Indexes start from 0. To use all of the indexes in your array you can use @ as your index.

You can declare an empty array too. Here's how to do it:

declare -a <array_name>
  • declare: Bash command used to explicitly set the array variable attribute.
  • -a: Option indicating the declaration of an indexed array.
  • <array_name>: The name you want to assign to the array.
declare -a MyArray

For adding new values after declaration you can do either of these:

array_name[position]=value
  • array_name: The name of the array you assign.
  • position: The index at which you want to assign value.
  • value: The item you insert to the specified index.
MyArray[1]=one

or

array_name+=(item item item)
  • array_name: The name of the array you assign.
  • +=: Compound operator to add array elements.
  • item: Value you want to put in your array.
MyArray+=(one two three)


For loop

One of the ways of having loop is for loop. It reads each value of your array in each loop and puts it in a variable for later usage.

The for loop syntax is like:

for ItemsName in ArrayName;
do
    #Your code
done
  • ItemsName: The name of each value of your array. You can access it later as a variable inside the loop.
  • ArrayName: The name of the array you assigned.
  • do: Start sign of for loop. After this, your code should be placed.
  • done: End sign of for loop. Before this, your code should be placed.

For example:

Mylist=(one two three four five)
for item in ${Mylist[@]};
do
    echo $item
done
  • Mylist: The name of the array.
  • item: The name of each value of Mylist array.
  • ${Mylist[@]}: Calling the array with all of its indexes or values (by @ as the array index).
  • echo: Prints value to the output.
  • $item: Calling the local variable which contains one of the array's values in each loop.