Linux - Shell Script
![](/posts/linux/images/shell-script.png)
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 equalval1 -ne val2
Returns true if the values are not equalval1 -gt val2
Returns true if val1 is greater than val2val1 -ge val2
Returns true if val1 is greater than or equal to val2val1 -lt val2
Returns true if val1 is less than val2val1 -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)