The is a good practise to put hash-band line at the beginning of each script to tell which shell should execute this script
#!/bin/bash
To make file executable use
chmod u+x file_name
Single quotes escape everything inside.
Double quotes don’t escape $, {}. But escape ~ (use $HOME instead).
Every unix command return result code. 0 means success. Other values are error codes.
To finish script execution run
exit exit_code
$? - exit status for last command
${#var} - the length of the string in a variable
-- - end of options command.
$(...) - runs command in subshell (inner variables does not appear in main shell)eval - gets the string and evaluates it as if you type it in the terminal$0 - script name$1 - get the first param of the script$2 - get the second param of the script$# - the number of script arguments“$@” - equivalent to “$1”, “$2”, .., “$N” (arguments in array)“$*” - equivalent to “$1 $2 $3… $N”(arguments in string)$$ - PID of current process$? - status of the last command$! - PID last command while (( $# )); do
echo $1
shift
done
shift - removes the first argument ($2 => $1, $3 => $2)
shift n - removes first n argumentsgetopts - parse script options (like -p). Stops on an argument which does not starts with -.
getopts opt_string var_name
“ab” will let your script handle an option -a and/or -b: to options that take an argument“a:b” will let a take an argument, but not bOPTARG - argument of an optionOPTIND - holds the index of the next argument to be processedgetopts returns false when no more options are leftgetopts handles erros for you. If anything goes wrong, the option variable var_name holds “?”“:bsr”“?” will be putted in var_nameOPTARG“:” in option var_nameOPTARGTo create variable and assign value to it (do not put space before or after = )
var_name=var_value
To extract variable value use
$var_name
To assign combo value use the following
greeting=”hello”
user_greeting=”$greeting, $USER”
$x“$x”To tell where you variable ends use braces {}
${var_name}
To read a line of input into variable use
read var_name
All variables have attributes. To set attribute use declare.
declare -p var_name - print attributes for a variable
To set variable as readonly
declare -r const_name=”some value”
To export variable to child process use:
export var_name
declare -x var_name
Note: you can not pass variable from child scirpt to parent. When you pass variable to sub process the attributes of this variables do not get passed.
declare -a var_name - declares an array variablex[0]=”some” - assigns value to 0 element of x array${x[0]} - retrives 0 value from an array${x[@]} or ${x[*]} - retrieves all values from an arrayar=(1 2 3 a b c) - creates array of 6 elements${#var_name[@]} - gets the array length${!var_name[@]} - gets all array indices (there can be gaps in the indices)declare -A var_name - declares dictionaryecho ${array[*]} - print all elements in arrayvar_name=$(cat <<some_custom_tag
multiline string
some_custom_tag
)
${var:-value} - will evaluate to “value” if var is empty or unset${var-value} - will evaluete to “value” if var is unset${var:=value} - if var was empty or unset, this evaluates to “value” and assigns it to var${var=value} - if var was unset, this evaluates to value and assigns it to vardeclare -i var_name - add integer attribute to a varibaledeclare +i var_name - removes integer attribute from a variablelet - C-like syntax for doing calculation
let n=100/2 - sets variable n to integer((..)) - arithmetic expression.
((++x))** - increment x variable((p=x/100))(p= $( ls | wc -l )*10)$((..)) - this is a substitution, not a command
if variable declared as integer:
declare -i x
x=”from max”
echo $x # 0
((..)) can be used in if. In this case: 0 is false, anything else is trueTo debug your bash script put ‘-x’ to shellband
#!/bin/bash -x
To run script in debug mode use
bash -x script_name
To show command only for some lines use
set -x
bash_code_to_debug
set +x
| -e - exists script whenever a command faild (but not with if, while, until, | , &&) |
shopt -s nocaseblob - ignore case with pathname expansionshopt -s extglob - enable extended pattern matchingshopt -s dotglob - include hidden files with path name expansionman testman [help [[help test [ 56 -gt 55 ] && echo true || echo false # true
test 56 -gt 55 && echo $? # 0
Test options:
| Expression | Meaning |
|---|---|
| [[ $str ]] | str is not empty |
| [[ -n $str ]] | str is not empty |
| [[ -z $str ]] | str is empty |
| [[ $str = pattern ]] | checks unix pattern matching |
| [[ $str=sometning ]] | always return true. Do not do like this! |
| [[ $str = ~sometning ]] | checks regular expression matching |
| [[ -e $filename ]] | checks if file exists |
| [[ -d $dirname ]] | checks if directory exists |
| [[ -s $filename ]] | check if file has size more than 0 |
| [[ -[rwx] $filename ]] | check if file is available for read/write/execute |
= is the same as ==To compare numbers (only integer supported)
[[ arg1 OP arg2 ]] - where OP: -eq, -ne, -lt, -gt
The condition syntax
if <condition or command>; then
<code>
elif <condition or command>; then
<code>
else
<code>
fi
!, &&, ||while - repeats code while test true
while test; do
code to be repeated
done
until - repeats code while test false
until test; do
code to be repeated
done
for - assign each word in words to var . Stops when no words are left. Do NOT quote words.
for i in {1..10}; do
echo $i
done
for VAR in WORDS; do
code
done
iterate through files in pwd
for file in *; do
echo $file
done
iterate through files according to template in pwd
for file in *.txt; do
echo $file
done
iterate till max
for (( i=0; i<max; i++ )); do
code
done
$ to get variable value for counter in `seq 1 20`; do
echo $counter
done
for counter in {1..20}; do
echo $counter
done
case
case WORD in
PATTERN1)
code for pattern1;;
PATTERN2)
code for pattern2;;
....
PATTERNNn)
code for pattern n;;
?)
code for not matching pattern
esac
|| and && - combines multiple commands depending on their result. Commands are executed in order, they do not use any priorites
[[ $1 ]] || echo “missing argument” - print error when there is no argument[[ $1 ]] || echo “missing argument” && exit 1 - always exits!!![[ $1 ]] || { echo “missing argument” >&2; exit 1; } - good way to check input params{ } - group commands
{ cmd1; cmd2; cmd3 }echo - display a line of text
printf - format and print data
To put argument in printf command use
printf "hello %s, how are you?\n" $USER
To put printf output to a variable use -v option
printf -v var_name “some_str”
read - reads input into a variable
read x
REPLY-n stop read at the new line-N reads exact number of characters-s will suspess otput (useful for passwords)-r dissallow escare sequences, line continuation (best practice to use this option)to read 2 variables at one time:
read var_1 var_2 var_1_value var_2_value
An Introduction to Linux I/O Redirection
0: Standart Input (stdin)
/dev/stdin
1: Standart Output (stdout)
/dev/stdout
2: Standart Error (stderr)
/dev/stderr
/dev/null - discards all data send to itInput redirection: <
grep milk < shoppingnotes.txt
Output redirection: >
ls > listing.txt
> - will overwite existing files>> - appends to the end of a filePipes
ls | grep x
Redirect a specific stream with N> (where N is the number of stream, 1 is default )
cmd 2>/dev/null - discards all errorsRedirect to a specific stream with >&N
>&2 - sends output to stderr2>&1 - redirects stderr into stdoutTo redirect all I/O for the whole script use exec (usefull for logging)
exec >logfile 2>errorlog
A command in a pipeline runs in a subshell
declare -i count=0
ls | while read -r; do ((++count)); done # do not increases global count
Examples
command > file - redirects out of a command to a filecommand > /dev/null - discards out of a commandcommand 2> file - redirects standart error stream to a filecommand | tee file - redirects standart ouput of the command to a file and backward to outputcommand > logfile 2>&1 - sending both error and ouput to a single fileTo define function use
function_name () { .. }
you can pass arguments to it
you can use input\output redirection
Exit a function with return
returns a status code, like exit
without a return statement, function returns status of last command
print to stdout
sum () {
echo $(( $1 + $2))
}
use status of last comman
start_with_a () {
[[ $1 == [aA]* ]];
}
To define function local variable use:
declare var_name
local var_name
To export function to subprocess use
export -f function_name
will be executed every time when function is run
fun () {} >&2
ls | some_func - function will not get input from the ls outputGet the length of the string
${#var_name}
Removing part of a string
Example string: i=/Users/reindert/demo.txt
${var_name#pattern} - removes the shortest match from the begining of a string
${i#*/} => User/reindert/demo.txt
${var_name##pattern} -removes the longest match from the begining of a string
${i##*/} => demo.txt
${var_name%pattern} - removes the shortest match from the end of a string
${i%.*} => /User/reindert/demo (remove extension)
${var_name%%pattern} - remove the longest match from the end of a string
${i%%*.} => txt
Search and Replace.
Example string i=mytxt.txt
${var/pattern/string} - substitute first match with a string
${i/txt/jpg} # myjpg.txt
${var//pattern/string} - substitute all matchs with a string
${i//txt/jpg} # myjpg.jpg
${i//[jx]/a} # matat.tat
${var/#pattern/string} - matches begining of the string${var/%pattern/string} - matches the end of the string
${i/%txt/jpg} # mytxt.jpg
To import code in the crrent shell proces use
source myscript
source has an allias .To run script in backgroud use
./myscript &
To keep you script running when you exit the terminal session use
nohup myscript &
To run script with lower priority
nice myscript
To run script with lower priority in background use
nohup nice myscript &
At will execute your script at a specific time
at -f myscript noon tomorrow
Cron will execute your script according to a schedule. Also we could use upstart for this purpose