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)
Navigating Between Lines

  • 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
Supporting Character classes includes:

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 Substitution

$(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
these variables can be used to assign command substitution:

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.

Special Parameters include:


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

Useful Commands


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:

Comments

Popular Posts