Linux - Shell Script

Shebang

On Linux, a shebang #! is a special line at the beginning of a script that tells the operating system which interpreter to use when executing the script. This line, also known as a “sharp-exclamation”, “sha-bang”, “hash-bang”, or “pound-bang”, is the first line of a dash and starts with #! followed by the path to the interpreter. The Shebang line is important because it allows you to run scripts written in any language, not just shell scripts, on a Linux system.

1#! /bin/sh
2#! /bin/bash
3#! /bin/tcsh
4#! /bin/csh
5#! /bin/ksh
6#!/usr/bin/env python2
7#!/usr/bin/env node
  • Example (use nodejs as interpreter)
1#!/usr/bin/env node
2console.log('Hello world!');

Echo Command

1echo Hello World!

Comments

Every line other than the first line (#! /bin/..) that STARTS with a '#'(pound/sharp/hash) marks a comment

1#!/bin/bash
2# Let's print something	=> A comment
3echo "Hello There"
4# End of printing => A comment

Variables

A variable name could contain any alphabet (a-z, A-Z), any digits (0-9), and an underscore ( _ ). However, a variable name must start with an alphabet or underscore.

NOTE: NO SPACES before or after the '='

1NAME="Bob"
2echo "My name is $NAME"
3echo "My name is ${NAME}"

System defined variables

To get the list of the SDV (system defined variables)

1env 

some of the important variables which are commanly used in shell script

  • ${SHELL}: Current shell interpreter information
  • ${HOME}: will show the home directory of current user
  • ${OSTYPE}: type type of operating system.
  • ${PATH}: A list of directories to be searched when executing commands.
  • ${PPID}: parent process id
  • ${PWD}: present working directory
  • ${HOSTNAME}: hostname of machine.
  • ${UID}: user id

Special variables

  • $0 - Check current script name
  • $n - Sequence of arguments
  • $# - To check count (number of arguments) in script.
  • $* - It stores complete set of positional parameter in a single string
  • $@ - Quoted string treated as separate arguments.
  • $? - exit status of command
  • $$ - Check PID of current shell.
  • $! - check PID of last background Job

Array

 1Fruits=('Apple' 'Banana' 'Orange')
 2
 3Fruits[0]="Apple"
 4Fruits[1]="Banana"
 5Fruits[2]="Orange"
 6
 7# Working with arrays
 8echo ${Fruits[0]}           # Element #0
 9echo ${Fruits[@]}           # All elements, space-separated
10echo ${#Fruits[@]}          # Number of elements
11echo ${#Fruits}             # String length of the 1st element
12echo ${#Fruits[3]}          # String length of the Nth element
13echo ${Fruits[@]:3:2}       # Range (from position 3, length 2)
14
15# Operations
16Fruits=("${Fruits[@]}" "Watermelon")    # Push
17Fruits=( ${Fruits[@]/Ap*/} )            # Remove by regex match
18unset Fruits[2]                         # Remove one item
19Fruits=("${Fruits[@]}")                 # Duplicate
20Fruits=("${Fruits[@]}" "${Veggies[@]}") # Concatenate
21lines=(`cat "logfile"`)                 # Read from file
22
23# Iteration
24for i in "${arrayName[@]}"; do
25echo $i
26done

Storing commands in variables

1VAR_NAME=$(command)
2VAR_NAME=`command`

Read user input

1read -p "Enter your name: " NAME
2echo "Hello $NAME, nice to meet you!"

IF Statement

1if [ "$NAME" == "Brad" ]
2then
3echo "Your name is Brad"
4fi

IF-ELSE Statement

1if [ "$NAME" == "Brad" ]
2then
3echo "Your name is Brad"
4else 
5echo "Your name is NOT Brad"
6fi

ELSE-IF (elif) Statement

1if [ "$NAME" == "Brad" ]
2then
3echo "Your name is Brad"
4elif [ "$NAME" == "Jack" ]
5then  
6echo "Your name is Jack"
7else 
8echo "Your name is NOT Brad or Jack"
9fi

Comparison

  • val1 -eq val2 Returns true if the values are equal
  • val1 -ne val2 Returns true if the values are not equal
  • val1 -gt val2 Returns true if val1 is greater than val2
  • val1 -ge val2 Returns true if val1 is greater than or equal to val2
  • val1 -lt val2 Returns true if val1 is less than val2
  • val1 -le val2 Returns true if val1 is less than or equal to val2
1NUM1=31
2NUM2=5
3if [ "$NUM1" -gt "$NUM2" ]
4then
5echo "$NUM1 is greater than $NUM2"
6else
7echo "$NUM1 is less than $NUM2"
8fi

File condition

  • -d file True if the file is a directory
  • -e file True if the file exists (note that this is not particularly portable, thus -f is generally used)
  • -f file True if the provided string is a file
  • -g file True if the group id is set on a file
  • -r file True if the file is readable
  • -s file True if the file has a non-zero size
  • -u True if the user id is set on a file
  • -w True if the file is writable
  • -x True if the file is an executable
1FILE="test.txt"
2if [ -e "$FILE" ]
3then
4echo "$FILE exists"
5else
6echo "$FILE does NOT exist"
7fi

CASE Statement

 1read -p "Are you 21 or over? Y/N " ANSWER
 2case "$ANSWER" in 
 3[yY] | [yY][eE][sS])
 4    echo "You can have a beer :)"
 5    ;;
 6[nN] | [nN][oO])
 7    echo "Sorry, no drinking"
 8    ;;
 9*)
10    echo "Please enter y/yes or n/no"
11    ;;
12esac

FOR LOOP

1NAMES="Brad Kevin Alice Mark"
2for NAME in $NAMES
3do
4    echo "Hello $NAME"
5done

Example - FOR LOOP TO RENAME FILES

1FILES=$(ls *.txt)
2NEW="new"
3for FILE in $FILES  
4do
5    echo "Renaming $FILE to new-$FILE"
6    mv $FILE $NEW-$FILE
7done

WHILE LOOP - READ THROUGH A FILE LINE BY LINE

1LINE=1
2while read -r CURRENT_LINE
3do
4    echo "$LINE: $CURRENT_LINE"
5    ((LINE++))
6done < "./new-1.txt"

FUNCTION

1function sayHello() {
2echo "Hello World"
3}
4sayHello

FUNCTION WITH PARAMS

1function greet() {
2echo "Hello, I am $1 and I am $2"
3}
4greet "Brad" "36"

Parameter expansions

 1name="John"
 2echo ${name}
 3echo ${name/J/j}    #=> "john" (substitution)
 4echo ${name:0:2}    #=> "jo" (slicing)
 5echo ${name::2}     #=> "jo" (slicing)
 6echo ${name::-1}    #=> "joh" (slicing)
 7echo ${food:-Cake}  #=> $food or "Cake"
 8
 9length=2
10echo ${name:0:length}  #=> "jo"
11
12# ---------------------------------
13
14STR="/path/to/foo.cpp"
15echo ${STR%.cpp}    # /path/to/foo
16echo ${STR%.cpp}.o  # /path/to/foo.o
17
18echo ${STR##*.}     # cpp (extension)
19echo ${STR##*/}     # foo.cpp (basepath)
20
21echo ${STR#*/}      # path/to/foo.cpp
22echo ${STR##*/}     # foo.cpp
23
24echo ${STR/foo/bar} # /path/to/bar.cpp
25
26# -----------------------------------
27
28STR="Hello world"
29echo ${STR:6:5}   # "world"
30echo ${STR:-5:5}  # "world"
31
32SRC="/path/to/foo.cpp"
33BASE=${STR##*/}   #=> "foo.cpp" (basepath)
34DIR=${SRC%$BASE}  #=> "/path/to" (dirpath)

Examples