Bash Scripting, often termed as one of the essential skills when you want to become Hacker. Often the guides are comprehensive, I am outlining bare minimum skills or topics we should understand regarding bash.
This article like many other is a progressive one, that is will be updated with more related contents.
#!/bin/bash
echo "Lets Learn Scripting"
While #
in bash means rest of the line is commented out, #!<path to shell/interpreter>
means which program will parse the script.
Usually this is the first line of script directing which interpreter to use.
How to Execute script ?
To execute the script, it should have executable permission , now you can set file permission to execute to one or more users groups to let it execute.
chmod 755 myscript.sh
./myscript.sh
Lets Learn Scripting
The script can be called/executed from the current directory with ./script-name.sh where ./ means its present in the current path, else the complete path has to be specified.
Various Shell Script interpreters
So in case you want the script to be processed by zsh ksh csh, specify respectively on the first line
#!/bin/zsh
#!/bin/ksh
#!/bin/csh
What happens when the shell/interpreter is not specified ? Script will execute using the current shell
Variables
VARIABLE_NAME="VALUE'
Also bash follows the usual naming convention like variable name should not begin with number, should not contain special symbols other than _.
Conventionally Uppercase, case sensitive, and no space before or after the = sign.
To use a variable precede with variable by a $
sign, or ${VARIABLE}
.
The {}
format is optional unless the variable is followed by something like below
#!/bin/bash
NAME="Hacker"
echo "Hello $NAME , hope you are Learning"
echo "Hello ${NAME} , hope you are Learning"
VERB="run"
echo "Hello Hacker what are you doing ?"
echo "Hey ! I am ${VERB}ing."
echo "Hey! I am $VERBing #//This is wrong as the variable name changed.
Assign Command to Variable
One might want to pass a command to variable name which executes and displays the result of command in place of variable.
So below is how to do that, instead of value pass the command enclosed in brackets and precede by $ like $(command)
#!/bin/bash
LINUX_KERNEL=$(uname -r)
echo "We are running Linux Kernel version - #{LINUX_KERNEL}
Variable Expansion
The we can write statements in bash in two ways, one being older. Enclosed in " "
and enclosed in' '
.
The difference is variables in " "
will expand or will behave differently when it encounters $ ' \
.
The below example should make it clear. See the output differs when enclosed in " "
and when enclosed in ' '
.
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ user=$(whoami)
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ host='EthicalHackX'
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ echo "I am $user on machine - $host"
I am abhinav on machine - EthicalHackX
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ echo 'I am $user on machine - $host'
I am $user on machine - $host
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$
Conditional Operators in Bash
What if you want to make the script test some conditions and decide the flow of script ? Yes you can do that and it is very simple.
[ condition to test ]
[ -e /etc/shadow ] — This checks if the mentioned part /etc/passwd exists.
There are a number of File operator tests in bash
-d True if file is a directory
-e True if file exists
-f True if file exists and is a regular file.
-r True if file exists and is readable.
-s True if file exists and has a size greater than zero.
-w True if file exists and is writable.
-x True if file exists and is executable.
More comprehensively explained at – https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html
-n STRING if string is not empty
-z STRING if string is empty
STRING1 == STRING2 True is strings are equal
STRING1 ≠ STRING2 True if strings are not equal
arg1 OP arg2 OP
is one of ‘-eq’, ‘-ne’, ‘-lt’, ‘-le’, ‘-gt’, or ‘-ge’. – equal to, not equal to, less than, greater than or equa to…
Decision Making in Bash using IF
We also need to make the programs testing some conditions, if [ condition ] then [ do this]
, let see.
if [ condition-is-true ]
then
command1
command2
fi
if [ condition-is-true ]
then
command1
command2
else
command3
command4
fi
First we test the if condition, if it evaluates to true, execute the commands specified in then, and end the block with reverse if – fi. If you want to test for condition not true, we can also have else part, which executes commands if the condition test evaluates not true. NOTE : else can be skipped if not true condition is not desired.
Multiple if else –> elif
if [ condition-is-true ] #dont forget the space after if
then
command1
elif [ condition-is-true]
then
command2
else
command3
command4
fi
Loops in Bash
For loop
for variable_name in item1 in item_n
do
command1
command2
commandN
done
#!/bin/bash
for food_name in burger pizza roll
do
echo "I want to eat $food_name"
done
Instead of putting the items in for loop like above,we can assign the list to a variable.
#!/bin/bash
food="burger pizza roll"
for food_name in $food
do
echo "I want to eat $food_name"
done
The loops or rather say the commands can be a one liner too like the example below.
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ foods="pizza burger noodles"
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ for food in $foods; do echo $food; done
pizza
burger
noodles
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ for food in pizza burger noodles; do echo $food; done
pizza
burger
noodles
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$
Accepting Input in Bash (STDIN)
read -p "PROMPT" VARIABLE_NAME
NOTE : This(STDIN) can also come from output of other programs/piped commands.
#!/bin/bash
read -p "Hello hacker, what's ur name ?" HACKER_NAME
echo " Hacker $HACKER_NAME is welcomed to Ethical Hacking Tutorials"
the -p switch is usual, want the input to be hidden ? Like a password, -sp (silent) will help.
the -p
switch is usual, want the input to be hidden ? Like a password, -sp
(silent) will help.
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ read -sp "Enter the Password : " PasswordValue
Enter the Password :
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$
Case Statements
What if there are too many cases arising and writing if-else is not a good idea, or say like a list of items to chose from will decide the consecutive actions, case statements are at our rescue
case EXPRESSION in
PATTERN_1)
#//patterns here can have special characters
STATEMENTS
#// statements to execute if the pattern matches
;;
#// ending a clause, another pattern can be added like the below
PATTERN_2)
STATEMENTS
;;
PATTERN_N)
STATEMENTS
;;
*)
#// default clause, when none of the patterns match
STATEMENTS
;;
esac #// ending the case statements , reverse of case - esac
#!/bin/bash
echo -n "Enter the name of a Programming Language: "
echo "" #// just a blank line
read PL
#read -p "Enter the name of a Programming Language: " PL
echo -n "$PL Programming Language was Developed by "
case $PL in
FORTRAN)
echo -n "John Backus"
;;
JavaScript)
echo -n "Brendan Eich"
;;
Limbo | "Go")
echo -n "Rob Pike"
;;
C)
echo -n "Dennis Ritchie"
;;
*)
echo -n "You Know Hack is a Language developed by Facebook"
;;
esac
Positional Parameters
If you made a script to accept some input and wondering how to pass the values to parameters here we go.
Parameters in bash are defined starting $0
, $1
, $2
and so on.
$0
is by default the script name/file passed to interpreter .
So if you want to execute script with parameters, the code and output are like below ( a very simple script).
#!/bin/sh
echo " This is paramenetr 0 -- $0 "
echo "This is parameter 1 given in bash -- $1 "
echo "This is parameter 2 given in bash -- $2 "
┌──(kali㉿ETHICALHACKX)-[~]
└─$ chmod 755 ./bash/parameters.sh 126 ⨯
┌──(kali㉿ETHICALHACKX)-[~]
└─$ ./bash/parameters.sh EthicalhackX Abhinav
This is paramenetr 0 -- ./bash/parameters.sh
This is parameter 1 given in bash -- EthicalhackX
This is parameter 2 given in bash -- Abhinav
We want to pass more parameters , say multiple parameters to same place ( we will see examples further how and where we can use these things/concepts).
Say you have to archive 10 users at once, or even remove users, expire user passwords and many more.
#!/bin/sh
echo " This is paramenetr 0 -- $0 "
echo "This is parameter 1 given in bash -- $1 "
for user in $@
do
echo "I am -- $user "
done
┌──(kali㉿ETHICALHACKX)-[~]
└─$ ./bash/variables.sh EthicalhackX Abhinav Learning Hacking Bash
This is paramenetr 0 -- ./bash/variables.sh
This is parameter 1 given in bash -- EthicalhackX
I am -- EthicalhackX
I am -- Abhinav
I am -- Learning
I am -- Hacking
I am -- Bash
The below are more constant variables in bash, have it for ready reference.
- $#: number of command line parameters that were passed to the script.
- $@: All the parameters sent to the script.
- $?: The end status of the last process to execute.
- $$: The Process ID of the current script.
- $USER: The user executing the script.
- $HOSTNAME: The hostname of the machine executing the script.
- $SECONDS: The number of seconds the script has been running for.
- $RANDOM: Returns a random number.
- $LINENO: Returns the current line number of the script.
Exit Status Codes
Every command executed returns an exit code ranging 0
to 255
where 0
is successfully executed, non 0
means otherwise.
This can be used for error checking or executing other commands based on exit status. Documentation or man-page can help more on exit status.
Below we can see when the ls command is successful , the status code is 0
, when otherwise, it is non 0
.
The status command of last executed process is returned by $?
.
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ ls /home/abhinav
Desktop Documents Downloads Music Pictures Public Templates Videos
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ ls /home/NON_EXISTING_DIR
ls: cannot access '/home/NON_EXISTING_DIR': No such file or directory
┌──(abhinav㉿ETHICALHACKX)-[~]
└─$ echo $?
2
an example where we are using the exit status to execute commands cehcking exit status in conditional statements.
#!/bin/sh
HOST="google.comasdwr" #just to throw an error, invalid domain being used
ping -c 1 $HOST
RETURN_CODE=$?
if [ "$RETURN_CODE" -ne "0" ]
then
echo "$HOST unrechable."
fi
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ./exit_status_1.sh
ping: google.comasdwr: Name or service not known
google.comasdwr unrechable.
&& and || and the exit status relation
&& =AND
if there are two commands linked with && like below, the second command only executes when the first command is successfully executed, in other words the exit status code returned from first command is 0 ( command executed successfully) , otherwise the second command won’t execute.
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ls -la && echo "Last command Executed with Exit Status $?"
total 12
drwxr-xr-x 2 abhinav abhinav 4096 Apr 13 23:55 .
drwxr-xr-x 15 abhinav abhinav 4096 Apr 13 23:49 ..
-rwxr-xr-x 1 abhinav abhinav 129 Apr 13 23:55 exit_status_1.sh
Last command Executed with Exit Status 0
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ls -RANDOM_ERRORFULL_ARGS && echo "Last command Executed with Exit Status $?"
ls: invalid option -- 'O'
Try 'ls --help' for more information.
|| = or
if two or more commands are linked with or which is || , the second or consecutive commands will only execute if the first command returns non 0 exit status which means failed. if the first command executes successfully, the other part linked with or - || would not execute.
So these && and || can be used to check for conditions like execute the other command only when a set of tasks have succeeded or failed likewise.
In the below example see how || or functions , when exit status code is – 0, the other command won’t execute, when it is non-0, the other command will execute.
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ls -la || echo "Last command Executed with Exit Status $?"
total 16
drwxr-xr-x 2 abhinav abhinav 4096 Apr 14 00:10 .
drwxr-xr-x 15 abhinav abhinav 4096 Apr 13 23:49 ..
-rwxr-xr-x 1 abhinav abhinav 129 Apr 14 00:10 exit2.sh
-rwxr-xr-x 1 abhinav abhinav 129 Apr 13 23:55 exit_status_1.sh
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ls -123qwe || echo "Last command Executed with Exit Status $?"
ls: invalid option -- '2'
Try 'ls --help' for more information.
Last command Executed with Exit Status 2
; Seperator
When we encounter ; instead of && or || , this simply means all the commands separated by ; will execute. They can be thought of independent command and execution does not depends on previous commands exit status.
command1 ; command2 ; command3
can be written/or thought of as below
command1
command2
command3
Exit Command Defined Explicitly
How do we define the exit status code explicitly ?
Mention exit {0,1,2,3….255} like exit 3 after a command. If no exit code is specified , the exit code of last command is considered.
Also if no code is specified in whole script, agin the last exit code of command in whole script is taken.
Always remember, whenever you mention exit code in shell script , on reaching there the execution of shell script stops. Say a part of your script at top had exit code mentioned, and when(if) the execution flow reaches there, that is going out of script completely and return exit status code will the the one what you defined. See the below example.
!/bin/bash
echo "Statement 1 : Learn Ethical Hacking"
exit 2
echo "Statement 2 : Belkome to hacklido
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ ./exit2.sh
Statement 1 : Learn Ethical Hacking
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$ echo $?
2
┌──(abhinav㉿ETHICALHACKX)-[~/bash]
└─$