Bash 101
Bash 101
Bash commands are synchronous. Which means Bash reads commands line by line
Therefore the newline character \n can be used to separate lines. for example, echo -e \n.
commands can also be separated with ;
Bash operates either in Interactive Mode (from the terminal), or Non-Interactive Mode (Bash Shell Scripts). Bash versions can be retrieved by querying the $BASH_VERSION system variable.
Bash Shell Initialization
When Bash is launch it will start with loading initialization commands which are stored in:
.bash_profile
.profile
.bash_profile hold defined variables which gets exported to the environment, and at the end of the file
should include a source ~/.bashrc command. This is used to tell bash to continue parsing its shell initialization file “.bashrc”
If .bash_profiles does not exist it will then parse .profile instead.
Bash Search Order
When bash searches for a command it will first check to see if there is an alias for it. Then Bash will search the $PATH environment variable. for example:
When the ping program is used it will search
PATH=/bin:/sbin:/usr/bin:/usr/sbin
│ │
│ ╰──▶ /sbin/ping ? found!
╰──▶ /bin/ping ? not found.
To find out where bash will find a program use the type -a command
To update the PATH env variable just set it with export PATH=<new location>
Types of shells
- C Shell (csh)
- Z Shell (zsh)
- Korn Shell (ksh)
- Bournse Shell (sh)
- Debian Almquist Shell (dash)
- Born Again Shell (bash)
- Ctrl + A: Move cursor to the beginning of the line
- Ctrl + E: Move cursor to the end of the line
- Ctrl + K: Delete from cursor to the end of the line
- Option + F: Move cursor one word forward
- Option + B: Move cursor one word backward
- Option + D: Delete next word
- Option + Delete: Delete previous word
Standard Input and Output File Descriptors
In order for programs to redirect their error messages to another file descriptor, it will half to instruct the kernel. Processes will inherit their file descriptors from Bash. These File Descriptors will connect Process streams to files, devices, and other processes streams are used to transport data between files and processes.
The following are the available File Descriptors:
Standard Input also called File Descriptor 0
By default, process will have their File Descriptor 0 connected to the keyboard.
Standard Output also called File Descriptor 1
By default, process will have their File Descriptor 1 connected to the monitors.
Standard Error also called File Descriptor 2
By default, process will send their error messages to File Descriptor 2.
File Redirections
File redirections can be used to redirect stdin or stdout messages.
for example
cat /etc/passwd > file.txt
To hide error messages, we can redirect file descriptor FD 2 to an non existent file
for example
cat /etc/passwd > file.txt 2>&1 file.txt
To redirect output and error messages to a file, use > >&
for example
for i in {1..255}; do nmap -sS 192.168.1.$i > scan.txt 2>&1 scan.txt; done
The <<< symbol can be used to read strings
for example
cat file.txt | nc >>> "127.0.0.1 809"
nc <<< "127.0.0.1 809"
Reading And Writing With File Redirections
To read a line from a file execute, read string <name_of_file
then execute echo $string
To read Nchars from a file execute, read -N 65535 string <name_of_file
then execute echo #$string
To write to a file the > redirection symbol can be used,
for example
echo "string" >~/path/to/file/file.txt
Copying File Descriptors
To copy results of a command to a file, including its output and error file descriptors
use > file.txt & 2>&1.
for example
ping 127.0.0.1 >results.txt 2>&1
Exec is used to execute commands, overwrite process, and change file descriptors #
to replace input file descriptor, use exec #>&1 to change it back use exec 1<&# #>&-
for example
exec 3>&1 >mylog; echo moo; exec 1>&3 3>&-
To replace output file descriptor, use exec #>&2 to change it back use exec 2<&# #>&-
for example
exec 6>&2 >log; ping 127.0.0.1 2<&6 6<&-
Appending File Redirection
The >> symbol can be used to append data to an existing file or file descriptor
Closing File Descriptors
To disconnect streams connected to standard output execute:
>&-
To disconnect streams connected to standard input execute:
<&-
Bash Script Writing
When writing a bash script, add the following hashbang
#!/bin/bash, this tells what interpreter to use to execute the instructions set in the script
When writing bash commands in a script, file extensions does not matter
Lists
A list is a sequence of commands that are separated with a control operator
Common control operators are a similcolon ; which tells bash that there is a new line
Theres || which tells bash to execute the second command if the first command fails
Theres && which tells bash to execute the second command if the first command executes
Compound Commands
Compound commands are block of sub commands stored within a single command
To place sub commands in a command list use { ;} or ()
for example
rm file.txt || { echo "Couldn't Delete file.txt" >&2; exit 1; }
or
if ! rm file.txt; then echo this file can't be deleted; fi
Functions
name () compound-command [ redirection ]
To define a functions first define the name of the function with name() then assign the sub commands to it or use the keyword function and then the function name followed with sub commands:
for example
function_name() ( <commands> )
function name_of_function { <commands>; }
Assigning Variables
To define a local variable inside a function use the keyword local
for example
functionname() {
local name= bob
}
To assign a variable to results returned by a command, use $( )
for example
listpass=$(cat /etc/passwd | cut -f1 -d":")
for i in $listpass; do id $1; done
To evaluate variables use
eval $name_of_variable
Passing Arguments
To pass arguments to a function identify them by there order number
for example
to pass the first argument specify $1,
function printname { echo "Hello: $1"; }
to pass the second argument specify $2,
function printname { echo "Hello: $1 $2"; }
Return Values
To define a return use the keyword return, however the return keyword must include a status value such as 0 for sucess or 1 if fail
for example
function test { if [ $EUID -eq 1 ]; then echo "ROOT"; return 0; else echo "NOT ROOT"; return 1; fi }
Comparing Conditions
Conditions are compared using [[ ]] and (( )), the difference is (( )) can perform arithmetic logic
for example
if [[ $var = <some condition> ]]
if (($var -gt 10 ))
Expansions
Expansions are used to replace arguments with situational arguments, it takes out the need for human interaction
for example
to remove files in a directory the * pathname expansion, can be used to remove any file in a directory:
rm /root/*
Expansions are performed by bash and before commands are executed
Supported Expansion glob patterns include:
- * - matches any kind of text
- ? - matches any one single character
- [A-Z][0-9] - set of characters to match a single character
- [[:classname:]] - pattern can match a type of character classes
alnum, alpha, ascii, blank, cntrl, digit, graph, lower, print, punct, space, upper, word, xdigit
To enable special expanded search patterns, execute shopt -s extglob
Special Glob patterns include:
- +(pattern[ | pattern ... ]) - Matches when any of the patterns in the list appears, once or many times over. Reads: at least one of ....
- *(pattern[ | pattern ... ]) - Matches when any of the patterns in the list appears, once, not at all, or many times over. Reads: however many of ....
- ?(pattern[ | pattern ... ]) - Matches when any of the patterns in the list appears, once or not at all. Reads: maybe one of ....
- @(pattern[ | pattern ... ]) -Matches when any of the patterns in the list appears just once. Reads: one of ....
- !(pattern[ | pattern ... ]) -Matches only when none of the patterns in the list appear. Reads: none of ....
$(command)
When leveraging sub commands call wrap the arguments with double quotes for example echo "The total number of word characters in this file is: $(read string << file.txt; wc $string)"
Bash parameters
Bash parameters are regions in memory were data is stored temporarily
These parameters include:
- Positional paramaters
- special paramaters
- shell variables
- Shell Variables
- Shell Variables are arguments assigned to a name
var="$()"
$var
Shell variables can also be appended using +=
for example
greeting=hello
greeting+=world
Positional Paramaters
Positional parameters are parameters with a positive integer, ${0} ${1}, ${2}
${0} is a variable that maps to the name of the process
${1} is the first parameter
${2} is the second parameter
Positional Parameters are read only, and can be set with the command set --
Positional Parameters can also be shifted by using the shift command for example
set -- ‘first argument’ ‘second argument’ ‘third argument’
echo “1: $1, 2: $2, 3: $3”
shift 2
the output will be third argument
Bash can pass in positional arguments using bash -c for example;
bash -c `echo “1: $1, 2: $2, 3: $3”1 -- ‘first argument’ ‘second argument’ ‘third argument’
Parameter Expansions
Parameter Expansions can be used to group variables by using Curly brackets {}
for example
name=bronson birthday=05/02/1986
echo "Hello $bronson; if [${birthday} = date]; then echo Happy Birthday; fi"
You can use the output file descriptor > to redirect contents of a variable to file and in the mean time change the pattern of the variable contents
for example
dog=wof
echo $dog > "${dog#+wof}.txt"
Parameters Expansions include:
Parameter | Example | Description |
---|---|---|
${parameter#pattern} | "${url#*/}" | Remove the shortest string that matches the pattern if it's at the start of the replacement. |
${parameter##pattern} | "${url##*/}" | Remove the longest string that matches the pattern if it's at the start of the replacement. |
${parameter%pattern} | "${url%/*}" | Remove the shortest string that matches the pattern if it's at the end of the replacement. |
${parameter%%pattern} | "${url%%/*}" | Remove the longest string that matches the pattern if it's at the end of the replacement. |
${parameter/pattern/replacement} | "${url/./-}" | Replace the first string that matches the pattern with the replacement. |
${parameter//pattern/replacement} | "${url//./-}" | Replace each string that matches the pattern with the replacement. |
${parameter/#pattern/replacement} | "${url/#*:/https:}" | Replace the string that matches the pattern at the beginning of the value with the replacement. |
${parameter/%pattern/replacement} | "${url/%.html/.jpg}" | Replace the string that matches the pattern at the end of the value with the replacement. |
${#parameter} | "${#url}" | Expand the length of the value (in bytes). |
${parameter:start[:length]} | "${url:7}" | Expand a part of the value, starting at start, length bytes long. You can even count start from the end rather than the beginning by using a (space followed by a) negative value. |
${parameter[^|^^|,|,,][pattern]},| "${url^^[ht]}" | "${url^^[ht]}" | Expand the transformed value, either upper-casing or lower-casing the first or all characters that match the pattern. You can omit the pattern to match any character. |
Parameter | Example | Description |
---|---|---|
"$*" | echo "Arguments: $*" | Expands a single string, joining all positional parameters into one, separated by the first character in IFS (by default, a space).Note: You should never use this parameter unless you explicitly intend to join all the parameters. You almost always want to use @instead. |
"$@" | rm "$@" | Expands the positional parameters as a list of separate arguments. |
"$#" | echo "Count: $#" | Expands into a number indicating the amount of positional parameters that are available. |
"$?" | (( $? == 0 )) || echo "Error: $?" | Expands the exit code of the last (synchronous) command that just finished.An exit code of 0 indicates the command succeeded, any other number indicates why the command failed. |
"$-" | [[ $- = *i* ]] | Expands to the set of option flags that are currently active in the shell.Option flags configure the behaviour of the shell, the example tests for the presence of the i flag, indicating the shell is interactive (has a prompt) and is not running a script. |
"$$" | echo "$$" > /var/run/myscript.pid | Expands a number that's the unique process identifier for the shell process (that's parsing the code) |
"$!" | kill "$!" | Expands a number that's the unique process identifier of the last process that was started in the background (asynchronously).The example signals the background process that it's time to terminate. |
"$_" | mkdir -p ~/workspace/projects/myscripts && cd "$_" | Expands to the last argument of the previous command. |
Arrays
An array is a parameter that can hold groups of data to assign an array use = ()
for example:
name=( bob james david )
elements in an array can be obtained by “${name[position]}”
To remove a specific item in a array use the unset command
for example:
unset “name[1]”
arrays support expansion parameters
for example:
echo “${name[@]}’
To append item to a list in a array use +=()
Arrays support glob patterns and positional arguments
Loops
for ((i = 1; i <= N; i++)); do
<loop content>
done
Testing Condition
test conditions are used to evalute a condition
for example:
read -p " "
if [$var = pram ]; then execute else execute fi
If statements
if list [ ;|<newline> ] then list ;|<newline>
[ elif list [ ;|<newline> ] then list ;|<newline> ] ...
[ else list ;|<newline> ]
fi
if [[ .. ]]
then
do a command
fi
nested if statements
#!/bin/bash
if [[ ... ]]
then
do command
if [[ ... ]]
then
do command
fi
fi
If Else
if [ <some test> ]
then
<commands>
else
<other commands>
fi
If Elif Else
if [ <some test> ]
then
<commands>
elif [ <some test> ]
then
<different commands>
else
<other commands>
fi
IF Operators
! - is false.
-n - STRING is greater than zero.
-z - The lengh of STRING is zero (ie it is empty).
= - string equals string
!= - string does not equal to string
-eq - interger is equal to
-gt - interger is greater then
-lt - interger is less then
-le - interger is less then or eqaul
-d - file exists and is a directory
-e - file exists
-s - file is not empty
-r - file exists and it has read permissions
-w - file exists and it has write permissions
-x - file exists and has execute permissions
Test Commands
$? holds exit status code ( 1 = Failure 0 = success )
Case Statements
case statements are used to pefrom switch statements
case statements are initiated using the keyword case
case statements are closed using ;;
for example
#!/bin/bash
case $1 in
synscan)
echo "Enter IP Address"; read response; nmap -sS -sV --top-ports 1000 $response
;;
udpscan)
echo "Enter IP Address"; read response; nmap -sU -sV $response
;;
esac
Conditional statements are wraped in [[ ... ]]
Loops
Loops can be used to perform a range of instructions based on a conditional counter
Loops are incremented by one using ++,
There are three types of loops
A while loop, until loop, and a for loop
While Loop
(a while loop will execute a command while a condition is true)
while [[ <some condition> ]]
do
<command>
done
for example
a while loop can be used to print from 1 to 10
counter=1
while [[ $counter -le 10 ]]
do
echo $counter
((counter++))
done
Until Loop:
a until loop will be used to execute a command until a condition is meet
when using a until loop start with leveraging the greater then condition
counter = 1
until [[ $counter -gt 3 ]]
do
ping 192.168.1.1
((counter++))
done
For loops:
a for loop will be used to execute commands based on elements in a list
for example
for var in <list>
do
<commands>
done
For loops can also perform commands from a given range using {1..#}
for example
for ip in {1..254}
do
nmap -sS -sV --top-ports 1000 192.168.1.$ip
done
A range can be increased by appliying {n..n..n}
for example to decrease 10 - 0 by 2, use {10..0..2}
for n in {10..0..2}
do
echo $n
done
For loops can also process set of files
for example
for file in $1/*.txt
do
cp $file $1/$( basename -s *.txt $file ).sh
done
Controlling Loops
Loops can be controlled through break, continue statements
The break statement tells bash to exit the current loop
for example
#!/bin/bash
for items in <list>
do
<some command>
if [[ $var = <some condition> or "meets some condition, -gt 5" ]]
then
<execute some command based on the tiggered condition>
break //this will tell bash to stop the if loop immediately
fi //closes the if statement
execute command <for items in list>
done
The continue statement tells bash to Stop this iteration of the loop and begin the next iteration.
for example
#!/bin/bash
for items in <list>
do
if [[ $var = <some condition> or "meets some condition" ]]
then
execute <command>
continue //stops peforming if loop and continue the for loop
fi
execute command <for items in list>
done
Select Statements
Select statement can be used to build a menu system
it takes items in a list, assigns an associated number to them, and displays them. System variable PS3 can be used
to display a prompt
for example:
#!/bin/bash
# A simple menu system
names='Kyle Cartman Stan Quit'
PS3='Select character: '
select name in $names
do
if [ $name == 'Quit' ]
then
break
fi
echo Hello $name
done
echo Bye
time - The time command is used to tell how long a command has executed for
rev - reverse string
basename - basename is used to strip / in a filepath and output the filename or directory name
xargs - xargs can be used to instruct bash to do something based on the results from a previous command in a single line, for example find -name "*.txt" | xargs grep "passw"
read - read command can be used to retrieve standard input and store the input into a buffer.
{ # .. # } - specifies range between N-number through N-mumber
& - executes in the background
; - separate order of operations
$ - Dollar Signs assigns variables
(cmd) - execute command operation in subshell
! - performs if not statement
` - backtick can be use to substituted a command with another command
for example:
http://website.com/index.php?command=ping -c4 127.0.0.1`nc 127.0.0.1 8080`
fi - closes if statements
$< - Reads input from terminal.
/ - escape characters
" " - qoutes characters
spaces causes bash to skip to the next unit of characters
CoProcess
coprocess is a asynchronous command that can be executed without having bash to wait, and gets executed in the background
coproc [ name ] command [ redirection ... ]
Coprocess can be used to build pipes between commands, it can connect other commands input or output results
for example
coproc name {command ;}
read results <&"{name[0]}"
echo "$results"
References:
Useful Cheat Sheet https://github.com/wvu/talks/blob/master/defcon/26/One-Liners%20to%20Rule%20Them%20All.pdf
Script to generate bash templates: http://bash3boilerplate.sh/
Script to generate bash templates: http://bash3boilerplate.sh/
Comments
Post a Comment