common usages
check available shell
cat /etc/shells
#check current shell
echo $SHELL
multiline comments
use : ‘ and ‘ for multiline comments
Here Document
The content between the two delimiters (Here Document Content part) is passed to cmd as an input parameter
cat << EOF
First Line
Second Line
Third Line EOF
EOF
conditional statement
if [$num -gt 5] && [$num -lt 10]
then
echo "in range 5 and 10"
elif [$num -lt 5] || [$num -gt 10]
echo "not in range 5 and 10"
else
echo "not equal!"
fi
for loop
for i in {1..5}
#for i in $(seq 1 2 10)
do
echo $i
done
string processing
#length of string
echo $(#str_name)
#cat string
newstring=$str1$str2
arithmetics
echo $((num1 + num2))
#or
echo $(expr $num1 - $num2)
echo $((num1 * num2))
#or
echo $(expr $num1 \* $num2)
#convert hex to decimal
echo "obase=10; ibase=16; $hex" | bc
declare statement
declare [-aixr] variable
-a: Define the following variable as an array
-i: Define the following variavle as an integer number
-x: The usage is the same as export, which is to turn the following variable into an environment variable
-r: Set a variable to read-only. Reading the variable cannot change the content, nor can it unset
check file and directory
if [-d $dir]
then
echo "it is a directory"
fi
if [-f $file]
then
echo "it is a file"
fi
filter
grep
#check if pattern exists in logfile
grep -q $pattern $logfile
#print a line not containing the pattern
grep -v $pattern $logfile
#print a line ignoring case in pattern
grep -i $pattern $logfile
#print a line after teh matched pattern
grep -A1 $pattern $logfile
#print a line before teh matched pattern
grep -B1 $pattern $logfile
awk
#print entire file contents
awk '{print}' $filename
#print lines containing pattern
awk '/root/ {print}' $filename
#print 3th columns of the line containing pattern
awk '/root/ {print $3}' $filename
sed
#replace first matching of root with other word groot
sed "s/root/groot/" $filename
#replace all matching
sed "s/root/groot/g" $filename
#replace and write change to file
wed -i "s/root/groot/g" $filename
array
#define array
$ declare -A userdata
$ userdata[name]=seth
$ userdata[pass]=8eab07eb620533b083f241ec4e6b9724
$ userdata[login]=`date --utc +%s`
#view entire array
$ typeset -A
#remove item from array
$ unset userdata[pass]
$ unset "userdata[*]"
Tips
start line
#!/usr/bin/env bash
arguments
if [[ $# != 2 ]];then
echo "Parameter incorrect."
exit 1
fi
double quotes
#!/bin/sh
#as known there is an a.sh file in current folder
var="*.sh"
echo $var
echo "$var"
#output
a.sh
*.sh
use main
#!/usr/bin/env bash
func1(){
#do sth
}
func2(){
#do sth
}
main(){
func1
func2
}
main "$@"
default variable scope is global
#!/usr/bin/env bash
var=1
func(){
var=2
}
func
echo $var
#output
2
return value
return value of function can only be integer, but there are some work-arounds for string return value
func(){
echo "2333"
}
res=$(func)
echo "This is from $res."
Indirect reference
VAR1="2323232"
VAR2=VAR1
eval $VAR1=233
echo ${!VAR1}
heredocs to file
write multiline contents to file
cat>>/etc/rsyncd.conf << EOF
log file = /usr/local/logs/rsyncd.log
transfer logging = yes
log format = %t %a %m %f %b
syslog facility = local3
EOF
path
script_dir=$(cd $(dirname $0) && pwd)
script_dir=$(dirname $(readlink -f $0 ))
keep code short
#bad
cat /etc/passwd | grep root
#good
grep root /etc/passwd
#bad
find . -name '*.txt' |xargs sed -i s/233/666/g
find . -name '*.txt' |xargs sed -i s/235/626/g
find . -name '*.txt' |xargs sed -i s/333/616/g
find . -name '*.txt' |xargs sed -i s/233/664/g
#good
find . -name '*.txt' |
xargs sed -i "s/233/666/g;s/235/626/g;s/333/616/g;s/233/664/g"
Parallelization
parallelization with “&” and “wait” commands
func(){
#do sth
}
for((i=0;i<10;i++))do
func &
done
wait
text search
find . -name '*.txt' -type f | xargs grep 2333
#if there is space in .txt name then
find . -type f|xargs -i echo '"{}"'|xargs grep 2333
standard input
$#–>number of input parameter $@–>all input parameters
switch
select cart in amazon flipkart local
do
echo "$cart is selected"
case $cart in
amazon)
echo "this is amazon";;
flipkart)
echo "this is flipkart";;
local)
echo "this is local";;
*)
echo "no option, please reselect.."
esac
done ### while
which [true]
do
read -t 3 key
if [$? -eq 0]
then
echo "terminating scipt..."
exit
else
echo "wait for input..."
fi
done
source
you can import function defined in other bash script using source, and use that function in that script
parse config file
#conf.cfg
user="tim"
#conf_parse.sh
MYCONFIG="conf.cfg"
function parse_config(){
CONFIG=$1
cat $CONFIG | cut -d"=" -s -f1,2 > /tmp/temp.cfg
source /tmp/temp.cfg
}
parse_config $MYCONFIG
curl
#GET
curl -s http://test_url.com
#POST
curl -k -X POST http://test_url.com --data @data.json -H "Content-Type: application/json"
#use jq to handle response
curl -s http://test_url.com | jq
curl -s http://test_url.com | jq -r .data[0] > response.json
debugging
-x will print out command in bash file line by line
bash -x test_debug.sh
bash history
History control
#set history upper limit
export HISTSIZE=3000
#force Bash to exclude commands starting with empty space
export HISTCONTROL=$HISTCONTROL:ignorespace
#avoid duplicate entries
export HISTCONTROL=$HISTCONTROL:ignoredups
Remove command from history
history | tail
history -d <history command id>
#clear entire session history
history -c
BATS test
BATS is used to test bash script
installation
git submodule init
git submodule add https://github.com/sstephenson/bats test/libs/bats
git submodule add https://github.com/ztombol/bats-assert test/libs/bats-assert
git submodule add https://github.com/ztombol/bats-support test/libs/bats-support
git add .
git commit -m 'installed bats'
to clone a git repo with BATS module you need:
git clone --recurse-submodules
refactor bash files
bash script should be splited into small functions and putting all to be execuated function in run_main for better test execuration.
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]
then
run_main
fi
bats test file
test files are .bats files in test folder, by adding following to test files and chmod +x will make them direct execuable.
#!/usr/bin/env ./test/libs/bats/bin/bats
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
@test "requires CI_COMMIT_REF_SLUG environment variable" {
unset CI_COMMIT_REF_SLUG
assert_empty "${CI_COMMIT_REF_SLUG}"
run some_command
assert_failure
assert_output --partial "CI_COMMIT_REF_SLUG"
}
bats test file supports loading bash libs
load 'libs/bats-support/load'
load 'libs/bats-assert/load'
load 'helpers'
load 'docker_mock'
mock function
function cat() { echo "THIS WOULD CAT ${*}" }
export -f cat