Learning Python and Bash: Week 2 – Mastering Shell Script Fundamentals

MRIDUL TIWARIMRIDUL TIWARI
9 min read

This week, I couldn’t work much on Python scripts or bash scripts, so I ended up practicing bash for a while, for which I will share the GitHub repo of all the code I created

I started revising my bash concepts. Realizing that most of the tasks that I was previously doing via Python script could be automated through bash scripts, and how much easier it is to write in bash. Here is a list of concepts I learnt regarding Bash Script

  • A bash script is a file containing a sequence of commands that are executed in order by the shell

  • Shell scripting is used for automation, system administration, and task scheduling

Adding variables in Shell

#!/bin/bash
name="John"
echo "Hello, $name!"
# O/P:
# Hello, John!
  • Command line arguments ($1, $2, ...)

      #!/bin/bash
      echo "First argument: $1"
      echo "Second argument: $2"
      # run it
      ./myscript.sh Linux shell
      # O/P:
      # First argument: Linux
      # Second argument : shell
    

Conditional Statements

  • If-else Statement
#!/bin/bash
if [$1 -gt 10 ]; then
echo "Number is greater than 10"
else
echo "Number is 10 or less"
fi
# Run:
./myscript.sh 15
# O/P:
# Number is greater than 10

Case statement

#!/bin/bash
echo "Enter a fruit name:"
read fruit
case $fruit in 
apple) echo "You chose Apple";;
banana) echo "You chose Banana";;
*) echo "Unknown fruit";;
esac

Loops

  • For loop
#!/bin/bash
for i in {1..5}; do
echo "Number : #i"
done
  • While loop
#!/bin/bash
count=1
while [$count -le 5]; do
echo "Count: $count"
((count++))
done

Functions

#!/bin/bash
greet(){
    echo "Hello, $1!"
}
greet "Alice"

Reading User Input

#!/bin/bash
echo "Enter your name:"
read name
echo "Hello $name!"

File Operations in Shell Script

# Check if a file exists
if [-f "myfile.txt"]; then
echo "File exists"
else
echo "File does not exist"
fi
# Append to a file
echo "New Line" >> myfile.txt

Scheduling Scripts with cron

0 2 * * * /path/to/backup.sh

  • List scheduled cron jobs

crontab -l

  • Basic Shell Scripts

    • Input and Output of Script

    • if-then Scripts

    • for Loop Scripts

    • do-while Scripts

    • Case Statement Scripts

    • Check Remote Servers Connectivity

      • When working with remote servers , its important to check connectivity before performing any operations

        • Using ping (Check if server is reachable)
            ping -c 4 remote-server

            # sends 4 pacjets to test if the server is reachable

            # if the server is down, you'll see packet loss
  • Using nc (Check if a specific port is open)
    nc -zv remote-server 22

    # Check if port 22 (SSH) is open on the remote server

    # If successful, it will return "Connection Successful"
  • Using telnet (Test port connectivity)
telnet remote-server 80

# Test if port 80 (HTTP) is accessible

# If connected, you'll see a blank screen; press CTRLL+ ], then type quit to exit
  • Using ssh (Check if SSH works)
ssh -v user@remote-server

# Adds verbose mode (-v) to see SSH connection details
  • Using traceroute (see the path of the connection)

      traceroute remote-server
    
      # shows each netwokr hop taken to reach the remote server
    

Aliases (alias)

  • These are shortcuts for frequently used commands

  • Create a Temporary Alias

alias ll="ls -lah"

# Now typing ll wil run ls -lah

# This alias is temporary (lost when you log out)
  • Create a Permanent Alias
# add then to ~/.bashrc to ~/.bash_profile

echo "alias ll='ls -lah'" >> ~/.bashrc

source ~/.bashrc

#the alias will now persist across reboots
  • User and Global Aliases

    • Each user can define aliases in ~/.bashrc or ~/bash_profile
    nano ~/.bashrc
    # Add:
    alias gs="git status"
    # Apply changes
    source ~/.bashrc

    ## FOR SYSTEM WIDE OR GLOBAL ALIASES
    nano /etc/profile
    alias cls="clear"
    # Apply changes
    source /etc/profile
  • Shell History (history)

    • shell keeps track of all executed commands
    history
    # shows recently executed commands

    !100
    # Run command no. 100 from history

    history -c
    # CLears the current session's history

    history -d 101
    # deletes a specific command number 101 from history

    # SET how many commands to store
    # By default bash keeps 500-1000 commands in history
    # You can chagne this

    export HISTSIZE=2000

    export HISTFILESIZE=5000
    # Saves 2000 commands in memory and 5000 in history file

Check Empty file

  • Using s (Checks if File is NOT Empty)

    The -s operator checks if the file exists and has a size greater than 0 (not empty).

#!/bin/bash
file="example.txt"
if [ -s "$file" ]; then
    echo "The file is NOT empty."
else
    echo "The file is empty."
fi

Best practice: Use -s when checking for non-empty files.


  • Using z "$(cat file)" (Checks if File is Empty)

    The -z operator checks if a string is empty. Combined with cat, it checks if the file has content.

      #!/bin/bash
      file="example.txt"
      if [ -z "$(cat "$file")" ]; then
      echo "The file is empty."
      else
      echo "The file is NOT empty."
      fi
    

⚠️ Downside: Uses cat, which is inefficient for large files.

  • Using wc -c (Checks File Size)

    You can also use wc -c (word count, character count) to check if a file has 0 bytes.

      #!/bin/bash
      file="example.txt"
      if [ "$(wc -c < "$file")" -eq 0 ]; then
          echo "The file is empty."
      else
          echo "The file is NOT empty."
      fi
    
  • Best when you need an exact byte count.


Concepts

  • Specify the command Interpreter

    • the #! notation -. Shebang or hash-bang, starts the first line of script as an interpreter directive for bash syntax script files

    • #!/usr/bin/bash → specify that the script must be executed using the bash shell located at the location /usr/bin/bash

  • What happens when you run a script?

    • OS Read Shebang

    • Interpreter Execution → OS uses the specified interpreter to execute the script

    • Options are applied → if options are specified, they are passed to the interpreter before the script is run

    • Without Shebang → if no shebang, the script might still work if you explicitly mention it with an interpreter

    • #!/usr/bin/bash -x

      • -x → tells bash to print each command before executing (for debugging)

      • -e → exits immediately if any command fails to ensure the script stops execution upon encountering an error

  • If a filename is - Then, when you try to vim or cat it, it will not open, cause Linux thinks “- “ as stdin or stdout, not a filename, for it to interpret it as you wanting to open that file use, cat ./-

  • which $SHELL → Check what shell you are running

  • When you first launch the shell, it runs a startup script that is defined in .bashrc or .bash_profile

  • A shell script is run line by line

  • Positional arguments can be assigned using $1 $2 $3

  • For other arguments, use read or read -p

  • Running in the background by adding & (ampercent) at the end of the command

  • case statement

      #!/bin/bash
    
      # | separator in case statement
      case ${1,,} in
              hearbert | administrator)
                      echo "HELLO m you are the boss"
                      ;;
              help)
                      echo "JUST enter"
                      ;;
              *) # catch all options
                      echo "DEFAULT"
      esac
    
  • Array

    • Array ⇒ MY_LIST=(one two three four five)

    • if you just try echo $MY_LIST → it will onyl return first element

    • to see the entire arary use echo ${MY_LIST[@]}

    • for index → ${MY_LIST[1]}

  • function

sed command

sed → stream line editor for real time editing in files or suing regular expressions

  • $0 - The filename of the current script.|

  • $n - The Nth argument passed to script was invoked or function was called.|

  • $# - The number of argument passed to script or function.|

  • $@ - All arguments passed to script or function.|

  • $* - All arguments passed to script or function.|

  • $? - The exit status of the last command executed.|

  • $$ - The process ID of the current shell. For shell scripts, this is the process ID under which they are executing.|

  • $! - The process number of the last background command.|

Trap

  • It often comes the situations that you want to catch a special signal/interruption/user input in your script to prevent the unpredictables.

Trap is your command to try:

  • trap <arg/function> <signal>
trap "echo Booh!" SIGINT SIGTERM
echo "it's going to run until you hit Ctrl+Z"
echo "hit Ctrl+C to be blown away!"

while true        
do
    sleep 60       
done

file tests commands

  • -e → to test if file exist

  • -d → to test if directory exist

  • -r → to check if the file has read permission for the user

#!/bin/bash
if [ -e "$filename" ]; then
    echo "$filename exists as a file"
fi

if [ -d "$directory_name" ]; then
    echo "$directory_name exists as a directory"
fi

if [ ! -f "$filename" ]; then
    touch "$filename"
fi
if [ -r "$filename" ]; then
    echo "you are allowed to read $filename"
else
    echo "you are not allowed to read $filename"
fi

Process Substitution

Process substitution allows a process’s input or output to be referred to using a filename. It has two forms:

  • output <(cmd),

  • input >(cmd).

Using diff file1 file2 could generate false positives in the case lines are not ordered. So if you want to compare those files you could create two new files, ordered, and compare those. It would look like:

# You can turn this
sort file1 > sorted_file1
sort file2 > sorted_file2
diff sorted_file1 sorted_file2

# into this
diff <(sort file1) <(sort file2)

Imagine you want to store logs of an application into a file and at the same time print it on the console. A very handy command for that is tee.

# turn this
echo "Hello, world!" | tee /tmp/hello.txt

# to this (only lower case in the file and uppercase in output)
echo "Hello, world!" | tee >(tr '[:upper:]' '[:lower:]' > /tmp/hello.txt)

sort command

  • The sort command in Linux is a utility used to sort lines of text files or standard input. By default, it sorts lines alphabetically in ascending order

  • -r → Reverse sort

  • -n → numeric sort

  • -u → remove duplicate

  • -k → sort by specific field/column

  • -t → Specify field separator

  • > or -o→ save output to new file

  • -c → check if sorted


Python and Bash scripts for learning different real-life use cases in Linux: Github Link

0
Subscribe to my newsletter

Read articles from MRIDUL TIWARI directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

MRIDUL TIWARI
MRIDUL TIWARI

Software Engineer | Freelancer | Content Creator | Open Source Enthusiast | I Build Websites and Web Applications for Remote Clients.