Bash

What is BASH?

BASH stands for the Bourne Again SHell, which is based on the UNIX C Shell and the Korn Shell. It is POSIX2 compliant.

The shell is the way users or scripts communivate with the Kernel. See https://askubuntu.com/questions/161511/are-the-linux-utilities-parts-of-the-kernel-shell for info on shells and kernels.

Bash Config files

Your home directory will containup to 3 files for configuring BASH, the default system wide file is /etc/profile, but ~/.bash_profile will override this. It is read every time you log in.

~/.bashrc is run each time you start a subshell.

~/.bash_logout is run when a login shell exits.

~/.bash_history is not really a config file, but stores a list of the commands you have run.

Quick guide to shell scripts in BASH

Generic script frameworks

Developed over time, these are frameworks which allows me to concentrate on the purpose of the script, the “boilerplate” code is already written and handles the boring stuff such as parsing input, reporting errors and writing log files.

Generic script framework for non-interactive scripts

Generic script framework for interactive scripts

Misc

tab=$(echo -en “\t”)

bash-3.00$ tab=$(echo -en "\t")
bash-3.00$ echo "test $tab test"
test     test
bash-3.00$ echo "test${tab}test"
test    test
bash-3.00$ echo "test${tab}${tab}test"
test            test
bash-3.00$

Specifying the base of a number

value too great for base probably refers to an arithmetic operation on a single 8 or 9 with a leading 0, ie. 08 or 09. Bash assumes this is an octal number from the leading 0 but 8 & 9 are not legal octal characters. You can specify the base of a number using base#number, usage is:-

RTTMP7=$((10#$RTTMP6 + 10#$RTTMP4))

Running multiple commands

Join two or more commands together, just rune them in turn and don't care if they succeed or fail:-

$ command1 ; command2

Logical AND, first command must succeed or second won't get run:-

$ mkdir newdir && cd newdir

Logical OR, runs second command when 1st fails:-

$ [-d newdir ] || mkdir newdir

Combining them:-

$ [-d newdir ] || mkdir newdir && cd newdir

Comparisons

Arithmetic Comparisons
-lt <
-gt >
-le
-ge >=
-eq ==
-ne !=
String Comparisons
= equal
!= not equal
< less then
> greater then
-n s1 string s1 is not empty
-z s1 string s1 is empty

Unlike setting variables where a space round the VARIABLE=value is required, comparison operators NEED a space round the operator, thinking on this, setting a variable and testing it are quite different operations, but the = and == for variable setting and testing numeric equality do superficially look similar.

if elif else

ACTION=${1}
if [ "${ACTION}" = "start" ]; then
        echo "Starting Apache instances"

elif  [ "${ACTION}" = "stop" ]; then
        echo "Stopping Apache instances"

else
        echo "No parameter passed, Useage:- startstopapache.sh start|stop"
        exit 2
fi

if with multiple conditions

#!/bin/bash

FABRIC=$1
if [ "${FABRIC}" = "" ]
 then
   echo "You need to provide a Fabric number, either 1 or 2"
   exit 1
fi
AND
if [ "${FABRIC}" != "1" ] && [ "${FABRIC}" != "2" ]
 then
   echo "Fabric values can only be 1 or 2"
fi
OR
if [ ${CPRESULT} != 0 ] || [ ${CPUSERRESULT} != 0 ]
        then
        THRESHOLD=1
fi

for loop

Specify a range of variables to work with

for i in {1..5}
for VARIABLE in bar boyl gm ppy   or for VARIABLE in `cat FILENAME`
do
      echo "WebSite is ${VARIABLE}, acton is ${ACTION}"
done

Exit from loop early

break causes the loop to quit, continue just exits the current iteration of the loop, it will just carry on with the next loop iterator value.

# use for loop read all GC servers
for (( gc=0; gc<${GCLENGTH}; gc++ ));
do
        echo "Using >${GLOBALCATALOG[$gc]}<"
        echo "==============================="
        echo ""

        ldapsearch -x -L -h ${GLOBALCATALOG[$gc]} -D "${CN}" -W -b "${SEARCHBASE=}" -s sub proxyAddresses
        LDAPSEARCHRESULT=$?

        if [ ${LDAPSEARCHRESULT} = 0 ]
          then
          break
        fi
done

while loop

while ($line = <SERIAL>) 
{
    print "$line\n";
}

Time duration of operation and record exit status

DURATION=$(time (tar -xvzf ${TARLOCATION}/ww-wiki-backup-${DAY}.tar.gz > /dev/null 2>&1) 2>&1)
TARRESULT=$?

echo "untar result is >${TARRESULT}<, " >> ${TMPLOG} 
echo -n "Explode return code is >${TARRESULT}<, it took" >> ${TMPLOG}
echo "${DURATION}" >> ${TMPLOG}
echo ""  >> ${TMPLOG}

Remove first or last character from variable

Use # for start of variable or % for the end of the variable.

[ scripts]$ FILE=admin.log.bz2
[ scripts]$ echo $FILE
admin.log.bz2

[ scripts]$ FILE=${FILE%.bz2}

[ scripts]$ echo $FILE
admin.log

Getting web page with wget

Basic use:-

$ wget --user='user' --password='pw' 'http://www.yoursite.com/index.html'

wget with login page and cookie is a two stage process. First, login and retreive cookie, secondly use this cookie to download resource:-

$ wget --save-cookies tmpcookies.txt --post-data 'user=user&password=pw' http://www.yoursite.com/login.html
 
$ wget --load-cookies tmpcookies.txt -p http://www.yoursite.com/protectedcontent.html

curl is somewhat similar:-

$ curl -u 'user:pw' 'http://www.yoursite.com'

Spinner.sh

#/bin/bash
# written Andrew Stringer 26/07/2013
#Aimlessly spins round waiting for something
 
function spinner() {
    local delay=0.75
    local spinstr='/-\|'
    printf "...\n"  
    while [ true ]; do
        local temp=${spinstr#?}
        printf "[%c]" "$spinstr"  
        local spinstr=$temp${spinstr%"$temp"}
        sleep $delay
        printf "\b\b\b" 
    done
}
 
echo "Waiting for 10s."
echo "================"
 
spinner &
LAST_SPINNER_PID=$!
 
sleep 10
 
kill ${LAST_SPINNER_PID}
 
echo ""
echo "Finished!"
echo ""
$ ./spinner.sh 
Waiting for 10s.
================
...
[-]
Finished!

Does directory exist

#!/bin/bash
 
DIR=H
 
if [ -d $DIR ]; then
	echo "Dir $DIR exists"
else 
	mkdir H
fi

Copy all files between directories

rsync -av src dest

Arrays

Bash array example, indices start at zero, so below [1] returns the second element ('example'):-

$ andrewsArray=(test example "three" 4)
$ echo ${andrewsArray[1]}
 
$ for i in ${andrewsArray[@]}; do
  ./pipeline --value $i
done
 
$ andrewsArray+=( "newItem1" "newItem2" )

Change user password from shell script

$ echo 'username:new_password' | sudo chpasswd

sed - stream editor

Remove comments starting with # from a file.

sed -e "/^#/d" <filename> > outputfile

-e is the regex expression (tautology noted…), ^ anchors to the start of the line, d deletes what is matched.

Remove last line of file

sed -i '$d' myfile.txt

-i allows sed to edit the file in place.

Testing content of zip file

I just want the files in a zip archive, without the Archive header or testing prefix added to each line. Also, as I need to compare zip files from a bash zip command and from a python equivalent, I want to sort them so diff can compare:-

$ unzip -t /tmp/boto3_python-1.26.59.zip  | more
Archive:  /tmp/boto3_python-1.26.59.zip
  testing: __pycache__/             OK
  testing: bin/                     OK
  testing: boto3/                   OK
  testing: boto3-1.26.59.dist-info/   OK
$ unzip -t boto3_python-1.26.59.zip  | sed 's/^    testing: //' | sed '/^Archive:/d' | sort > unzup-python-raw.txt

Default value for variable

read -p "AWS region [default is:- eu-west-2]:-" AWS_REGION
AWS_REGION=${AWS_REGION:-eu-west-2}

Remove and recreate directory

# remove any existing directories if they match the current release.
if [ -d "$LIB_DIR" ];  then rm -rf ${LIB_DIR}; fi
mkdir -p ${LIB_DIR}

This page has been accessed:-
Today: 1
Yesterday: 0
Until now: 174

 
linux/bash.txt · Last modified: 21/02/2024 16:43 by andrew