Shellman 2021 02 19
Shellman 2021 02 19
Remisa Yousefvand
This book is for sale at http://leanpub.com/shellman
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ii
Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
cmd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
CONTENTS
file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
archive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
http . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
ftp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
ip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
crypto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
lib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Argument Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Nested Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Colorful Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Factorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Preface
Shellman¹ is a vscode² snippet extension and is made to provide a high level interface for writing
shell scripts. That means easy way to accomplish the job without worrying about the details. As
long as you understand the interface and how it is organized, you are good. The trade-off is you
miss the details and it is also a good thing. After all that’s the purpose of abstraction. When you
need more control you can dig dipper and deal with details but before that stay at high ground as
much as you can.
When I started shell scripting, even with the best tools available I found it unorganized. I couldn’t
find easily how to do file, string, array… related operations. I didn’t care how a string is reversed
in shell scripting as long as it works (I know about best practices, performance, compatibility… but
they are not my primary concerns in a new field). Give some code the string abc which transforms
it to cba. If you are coming from a OOP background you expect³ such a function in String class.
So Shellman organizes such operations under related abstract groups called namespaces and I just
searched internet to find most fitting codes that do the job and organized them.
The hard part of shell scripting is not shell scripting itself, it is understanding Linux and knowing
the correct command and switches, so if you can do it in terminal, you can do it easily via shell script
too. Shell scripting is useful for common tasks automation.
This book is a guide for beginners who want to start shell scripting with Shellman effectively. If you
are of pragmatic type people then go ahead and read Basics section and desired namespaces. Also
the business model of Shellman is published on medium⁴.
Remisa Yousefvand
July 2020
¹https://marketplace.visualstudio.com/items?itemName=Remisa.shellman
²https://code.visualstudio.com
³From cognitive/statistical point of view, coming from OOP, or at least expecting order, you find Shellman convenient because its structure
matches your beliefs (prior). The probability distribution curve has the same shape, so you learn fast (little update to your curve is needed).
Your wishes about where to find a function just comes true.
⁴https://medium.com/@remisa.yousefvand/shellman-reborn-f2cc948ce3fc
Prerequisites
• vscode⁵ IDE
vscode download
• Shellman⁶ snippet
shellman install
⁵https://code.visualstudio.com
⁶https://marketplace.visualstudio.com/items?itemName=Remisa.shellman
Shellman Structure
Shellman divides its content into semantical categories named namespace. The concept is already
familiar to programmers, but in simple words it means keeping related materials together under a
generic name. So if you need to do something with String like changing it to upper case then it
makes sense to look at string namespace.
String Namespace
When you press ENTER on an item like above picture, vscode inserts some code into your script which
you can move into different parts using TAB key. This is called snippet. To access a snippet you start
typing and vscode shows a menu of snippets with matching prefixes.
Snippet Alias
When a snippet can be activated by two or more prefixes, a | between prefixes is used to
indicate that.
Shellman is structured into namespaces, so it is useful to know supported namespaces and their
members. There is no order in learning namespaces and you can learn them on need, but before
Shellman Structure iv
that, you need to know a few things about shell scripting. I will try my best to keep Basics section
short and simple so you can move fast to desired namespaces.
Shell Scripting Basics
Comments
In shell scripts, comments start with #. The exception is shebang which you see as the first line of
scripts.
1 # This is a comment
shebang
This is the first line of most of shell scripts. You may see different versions of it:
• #!/usr/bin/sh
• #!/usr/bin/bash
• #!/usr/bin/env bash
• …
This line tells the operating system which script engine should be used to run the script. Usually you
don’t need to change the default value Shellman provides:
1 #!/usr/bin/env bash
1 bash test.sh
Shell Scripting Basics 2
1 #!/usr/bin/env bash
2
3 rm some-file
If the command needs root⁸ privileges (in Windows it is known as Admin), prefix the command
with sudo:
1 #!/usr/bin/env bash
2
3 sudo rm some-file
If you need the result of the executed command refer to command substitution.
Multiline Command
A single command can be written in multiple lines if each line ends in a backslash.
⁷In Linux unlike Windows, file extensions has no special meaning to operating system but still you can use them to remember which file
type you are dealing with. vscode uses file extensions to recognize file types (.sh for Shellscript)
⁸In Linux/Unix systems, root is the most privileged user (same as Administrator in Windows).
Shell Scripting Basics 3
1 #!/usr/bin/env bash
2
3 curl --request GET -sL \
4 --user-agent 'Shellman' \
5 --cookie 'key=value' \
6 --url 'http://example.com'
1 #!/usr/bin/env bash
2
3 curl --request GET -sL --user-agent 'Shellman' --cookie 'key=value' --url 'http://ex\
4 ample.com'
You can write multiple commands in a single line and separate them by semicolon (;).
1 #!/usr/bin/env bash
2
3 var1=2; var2=3; var3="hello"
Variables
There is a simple difference between when you define a variable and when use its value. In latter
case you need to prefix a $ to the variable name (also you can write ${variable}).
Define a variable named firstName and set its value to Remisa:
1 firstName=Remisa
Now if we want to read our variable value and print in on screen with echo command we can write:
Shell Scripting Basics 4
1 firstName=Remisa
2 echo $firstName
3 # or
4 echo ${firstName}
1 #!/usr/bin/env bash
2
3 var=1
4 Var=2
5
6 echo "$var" # 1
7 echo "$Var" # 2
As you may guessed in assignment rule, space has a special meaning in shell scripting. With
space over = shell assumes variable is a command and = and variable value are parameters to that
command.
1 firstName = Remisa
2 # firstName: command not found
We should take care of where a space may appear. For example our variable value may contains
space:
1 fullName=Remisa Yousefvand
Now when we want to use fullName value we put a $ before it and use $fullName instead. But it
contains space and we need to take care of that. To do so, simply surround wherever whitespace
may appear in "":
1 fullName="Remisa Yousefvand"
2 echo "$fullName"
Consider you want to delete a file named some file.txt and you have save its name in a variable
like:
Shell Scripting Basics 5
1 fileName="some file.txt"
2 rm $fileName
With above script instead of deleting some file.txt you are telling rm to delete two files named
some and file.txt and you will get an error (No such file or directory).
1 a="Hello"
2 b="world"
3 c="!"
4 echo "$a $b$c"
5 # Hello world!
The whitespace between $a and $b is the whitespace between Hello and world in the output.
If you need adding more characters between variables then use "${variable}" syntax (this syntax
is recommended by many sources as the default syntax):
1 a="abc"
2 b="def"
3 c="ghi"
4 echo "${a}a ${b}b ${c}c"
5 # abca defb ghic
If we want to assign a variable if and only if it has no value currently, then we can use default value
snippet:
1 #!/usr/bin/env bash
2
3 : "${variable:=default}"
In above example variable is set only if it is empty. We will use this snippet later after argument
parsing to assign default values to variables when they are not passed (optional parameters) to script.
Shell Scripting Basics 6
Variable Types
There are three variable types in shell scripting: String, Integer and Array. Most of the time you
only need String. Even when working with numbers they are strings you pass to commands which
take care of converting those strings to numbers, do calculations, and return String back to you.
Although you can define variables using declare keyword, in this book we define variables literally.
1 # Number or Sting:
2 var1=1234
3 var2=12.56
4 var3="some text" # use double quote when there is a space in string
5
6 # Array:
7 myArray=("one" "two" "three")
8 # or
9 myArray2=(
10 "four"
11 "five"
12 "six"
13 )
14
15 echo "$var1" # 1234
16 echo "$var2" # 12.56
17 echo "$var3" # some text
18 echo "${myArray[@]}" # one two three
19 echo "${myArray2[@]}" # four five six
Function
Function in shell script is not what you expect from a function in other languages. They are like
commands defined in your script just like echo and ls. To define a function named myfunc simply
(there is a func snippet for that):
1 #!/usr/bin/env bash
2 function myfunc () {
3 echo "$1"
4 }
Function definition should precedes its usage. function keyword is optional and can be omitted:
Shell Scripting Basics 7
1 #!/usr/bin/env bash
2 myfunc () {
3 echo "$1"
4 }
To access function arguments we use $1, $2, $3… or access all of them at once through an array:
1 #!/usr/bin/env bash
2 function myfunc () {
3 arguments=("$@")
4 # arguments is the array variable containing all function parameters
5 }
If you need to return some value from a function use echo. There is a return keyword in bash but
you cannot use it for returning values from functions most of the time (unless your function return
an integer between 0 and 255) also it has its own meaning (0 for success and 1-255 for error codes).
If you want to terminate a function execution at some point use return (for example inside an if
statement).
1 #!/usr/bin/env bash
2 function myfunc () {
3 echo "this is the result"
4 # we don't need "return" here because function already reaches its end
5 }
1 function myfunc () {
2 echo "this is the result"
3 }
4
5 result=`myfunc`
6 echo "$result"
Commands
Command substitution
It is common practice to store the output of commands inside variables for further processing in
script. The process is known as command substitution and can be done in two syntaxes:
Shell Scripting Basics 8
1. output=`command`
2. output=$(command)
In most references method two is recommended because it is the only one that works with nested
command substitutions. For the sake of brevity and consistency, we will use method one (backtick)
in this book unless we need nested command substitutions (Also to be able to read and understand
shell scripts written by others).
To store results of ls command in a variable named output:
There is a more advance technique for using a command output as another command input, namely
piping (|), which is beyond the scope of this book (if you have functional programming background
you are already familiar with the idea).
Command success/failure
Programs return 0 in case of success and non zero if failure occurs.
To check that, you can read last command return value via $?. There is a snippet at func namespace
for retrieving last command return value as func ret val:
1 echo "$?"
Shellman supports checking failure of last command via cmd namespace as cmd failure check
snippet:
⁹This number is between 0 and 255 (one byte). If you have ever programmed in C/C++, you may noticed a return 0 as a default behavior,
that is the code your program is returning to OS, here 0 as success.
Shell Scripting Basics 9
1 touch /not-enough-permission-to-create-file
2
3 # check last command (touch) success/failure
4 if [[ $? != 0 ]]; then
5 echo "command failed"
6 fi
To check success, use cmd success check snippet from cmd namespace:
Check command exit code immediately after that command or you may get wrong result:
1 #!/usr/bin/env bash
2
3 touch /not-enough-permission-to-create-file
4
5 echo "checking operation..."
6
7 # check last command (echo) success/failure
8 if [[ $? != 0 ]]; then
9 echo "command failed"
10 fi
In above example your if statement won’t print the command failed message since last command
is echo and not touch.
Exit
It is a good practice to inform script caller (in case other scripts use yours) about success or failure
of your script. To indicate success:
Shell Scripting Basics 10
1 exit 0
And if an error happens use an exit code. Document exit codes at the top of of your script:
Argument parsing
By convention most Linux commands/programs supports a long and short version for the same
flag/switch. Short version is usually the first letter of the long version (unless it is taken, like adding
version to following list). Some examples:
short long
-v –verbose
-s –silent
-f –force
-o –output
You may want to support different switches/flags by your script and act differently based on them.
Suppose your script name is backup.sh. With supporting flags someone can run it as:
1 ./backup.sh -v
So your script works different with -v. For example you print verbose information. We need to know
if user has run our script with or without -v flag. Shellman makes it easy for you, keep reading.
If your script supports switches, it means user is passing some information to your script via that
switch. For example where to save the backup in our example:
1 ./backup.sh -o ~/my_backups
In above code we are telling the script to save the output in ∼/my_backups¹⁰ directory. Here -o is a
switch which takes one parameter (a path).
Flag vs Switch
Flag is used for boolean values and its presence means True while Switch accepts
argument(s).
1 POSITIONAL=()
2 while [[ $# > 0 ]]; do # while arguments count > 0
3 case "$1" in
4 -f|--flag)
5 echo flag: $1
6 shift # shift once since flags have no values
7 ;;
8 -s|--switch)
9 echo switch $1 with value: $2
10 shift 2 # shift twice to bypass switch and its value
11 ;;
12 *) # unknown flag/switch
13 POSITIONAL+=("$1")
14 shift
15 ;;
16 esac # end of case. "case" word in reverse!
17 done
18
19 set -- "${POSITIONAL[@]}" # restore positional params
The while loop keeps looping until there is no more arguments to process. Although the passed
arguments to your script would not disappear themselves, we trim them from left using shift
command. So if your script is executed like:
Input arguments are -m --name Remisa. After a shift they become --name Remisa and so on. So if
you need to process a switch with two arguments shift 3.
This snippet will take care of Flags and Switches of your script. For implementing your own flag(s)
replace -f|--flag with desired flag, i.e. -v|--verbose and on the next lines (before shift) do
whatever you need. It is recommended to define a variable and set it here to keep track of the
flag or store the value of switch parameter(s):
1 -v|--verbose)
2 verbose=true
1 -o|--output)
2 outputPath=$2
In above example we are saving the switch value in outputPath for using later. We refer to first
switch parameter with $2 and the second with $3 and so on because the $1 refers to the switch itself.
Then shift properly.
Repeat above procedure for more switches.
1 ./greet.sh
2 # good night everyone
3
4 ./greet.sh -m
5 # good morning everyone
6
7 ./greet.sh --name Remisa
8 # good night Remisa
9
10 ./greet.sh -n Remisa
11 # good night Remisa
12
13 ./greet.sh -m --name Remisa
14 # good morning Remisa
15
16 ./greet.sh -m -n Remisa
17 # good morning Remisa
Usually you only need 1, 2, 6, 9 from above list. argument parsing and setting default variable values
can be done in reverse order. In that case create a variables region after summary and set default
values. Later if argument parsing overrides some of your variables (passed as flag/switch) the rest
of variables contain default values.
In summary you provide some information about script.
1 #!/usr/bin/env bash
2
3 # Title: test
4 # Description: a test script
5 # Author: Remisa <[email protected]>
6 # Date: 2019-01-06
7 # Version: 1.0.0
8
9 # Exit codes
10 # ==========
11 # 0 no error
12 # 1 script interrupted
13 # 2 error description
Event handling
If you need to run a set of specific tasks before your script exits or in case user terminates your script
(pressing CTRL + C) you need to assign a handler function to appropriate event. The problem with
Shell Scripting Basics 14
event handlers is we use functions to run if a certain event happens so before assigning an event to a
function we need to write the function. To capture events as soon as possible we need to assign event
handlers early in our script. Thats why I have separated functions into two parts, event handlers,
at the top of the script just before binding events to them and the rest of functions which are not
needed so early. See event namespace for more information.
Use region snippet to define a functions region and put all of your functions there. Remember you
need to define functions before you can use them. If function B calls function A, then function A
definition should precede definition of function B.
1 #!/usr/bin/env bash
2
3 # summary here
4
5 # >>>>>>>>>>>>>>>>>>>>>>>> functions >>>>>>>>>>>>>>>>>>>>>>>>
6
7 function greet() {
8 # access the argument via $1
9 echo "Hello $1"
10 }
11
12 # <<<<<<<<<<<<<<<<<<<<<<<< functions <<<<<<<<<<<<<<<<<<<<<<<<
13
14 greet "Shellman" # call the function and pass an argument
1 var1="Hello World!"
2 echo "$var1" # Hello World!
3 # OR
4 echo "${var1}" # Hello World!
Double Quote
By default use Double Quote " when defining variable or trying to access a variable value.
Use single quotation where you need to define a variable that contains special characters. Anything
inside a single quotation will remain exact the same:
Shell Scripting Basics 15
1 var1="Hello World!"
2 echo "$var1" # Hello World!
3
4 var2='$var1'
5 echo "$var2" # $var1
6
7 var3='"&$*'
8 echo "$var3" # "&$*
Sample scripts
Apart from some examples in this book there is a samples directory¹¹ in project repository which
contains the steps and reasoning behind writing some shell scripts using Shellman.
¹¹https://github.com/yousefvand/shellman/tree/master/samples
Namespaces
Namespaces are semantic categories to hold related items together. Folders play the same role in
keeping related files together on a file system.
There is a length limitation to namespaces in a snippet so some of them doesn’t exist under exact
namespace I write in this book. Fortunately they are few.
It happens when a single snippet is not enough to do the job and a function is needed. Such functions
available in Shellman. See lib for more information.
Namespaces 17
loop
Contains while, until and for. Actually for doesn’t have loop prefix so by typing loop you won’t
see it. That’s because of readability limitations so if you need any kind of for type for.
while
while condition.
1 #!/usr/bin/env bash
2
3 a=3
4 while (( a > 0 )); do
5 echo "$a"
6 ((a--))
7 done
8 # 3
9 # 2
10 # 1
1 #!/usr/bin/env bash
2
3 str="s"
4 while [ "$str" != "end" ]; do
5 echo "start"
6 str="end"
7 done
8 # start
1 #!/usr/bin/env bash
2
3 while true; do
4 echo "message every 2 seconds"
5 sleep 2s
6 done
until
until condition (opposite of while).
1 #!/usr/bin/env bash
2
3 a=3
4 until (( a <= 0 )); do
5 echo "$a"
6 ((a--))
7 done
8 # 3
9 # 2
10 # 1
1 #!/usr/bin/env bash
2
3 str="s"
4 until [ "$str" == "end" ]; do
5 echo "start"
6 str="end"
7 done
8 # start
for i
for loop.
Namespaces 19
1 #!/usr/bin/env bash
2
3 for((i=0;i<5;i++)); do
4 echo "$i"
5 done
6 # 0
7 # 1
8 # 2
9 # 3
10 # 4
for i j
Nested for loop.
1 #!/usr/bin/env bash
2
3 for((i=0;i<3;i++)); do
4 for((j=0;j<2;j++)); do
5 echo "$i, $j"
6 done
7 done
8 # 0, 0
9 # 0, 1
10 # 1, 0
11 # 1, 1
12 # 2, 0
13 # 2, 1
for in
Iterate over ranges. Range can be numerical or alphabetical and can be defined as {start..end}.
Numerical range:
Namespaces 20
1 #!/usr/bin/env bash
2
3 for item in {1..5}; do
4 echo "$item"
5 done
6 # 1
7 # 2
8 # 3
9 # 4
10 # 5
alphabetical range:
1 #!/usr/bin/env bash
2
3 for item in {A..D}; do
4 echo "$item"
5 done
6 # A
7 # B
8 # C
9 # D
for in column
Sometimes output is arranged in multiple columns while we are interested in one or few of them.
For example output of docker images command:
1 #!/usr/bin/env bash
2
3 for col in `docker images | awk '{ print $1}'`; do
4 echo "$col"
5 done
1 REPOSITORY
2 sonatype/nexus3
3 sonatype/nexus3
4 busybox
5 busybox
If you need column two you can pipe (|) output of docker images to awk '{ print $2}':
1 #!/usr/bin/env bash
2
3 for col in `docker images | awk '{ print $2}'`; do
4 echo "$col"
5 done
1 TAG
2 3.13.0
3 latest
4 glibc
5 latest
logic
You can find logical related commands here under if namespace.
if
if, else condition.
1 #!/usr/bin/env bash
2
3 var1=32
4 var2=33
5
6 if (( $var1 == $var2 )); then
7 echo "equal"
8 elif (( $var1 >= $var2 )); then
9 echo "bigger"
10 else
11 echo "smaller"
12 fi
13 # smaller
1 #!/usr/bin/env bash
2
3 str1="bye"
4 str2="hello"
5 str3="bye"
6
7 if [ "$str1" = "$str2" ]; then
8 echo "1 = 2"
9 elif [ "$str1" = "$str3" ]; then
10 echo "1 = 3"
11 elif [ "$str2" = "$str3" ]; then
12 echo "2 = 3"
13 else
14 echo "no equal pair"
15 fi
16 # 1 = 3
1 #!/usr/bin/env bash
2
3 str1="bye"
4 str2="hello"
5
6 if [ "$str1" = "$str2" ]; then
7 echo "equal"
8 fi
or if/else:
1 #!/usr/bin/env bash
2
3 str1="bye"
4 str2="hello"
5
6 if [ "$str1" = "$str2" ]; then
7 echo "equal"
8 else
9 echo "NOT equal"
10 fi
11 # NOT equal
iff
If condition is true then run command (short circuit).
For arithmetic comparison use (( )).
1 #!/usr/bin/env bash
2
3 var=5
4 (( var > 3 )) && echo "greater than 3"
5 # greater than 3
1 #!/usr/bin/env bash
2
3 var="hi"
4 [ "$var" = "hi" ] && echo "hi"
5 # hi
iff not
If condition is false then run command (short circuit).
For arithmetic comparison use (( )).
1 #!/usr/bin/env bash
2
3 var=5
4 (( var > 8 )) || echo "less than 8"
5 # less than 8
1 #!/usr/bin/env bash
2
3 var="hi"
4 [ "$var" = "bye" ] || echo "hi"
5 # hi
if int =
Check if two integers are equal.
1 #!/usr/bin/env bash
2
3 int1=67
4 int2=67
5
6 if (( int1 == int2 )); then
7 echo equal
8 fi
if int !=
Check if two integers are not equal.
Namespaces 25
1 #!/usr/bin/env bash
2
3 int1=12
4 int2=13
5
6 if (( int1 != int2 )); then
7 echo not equal
8 fi
if int <
Check if the first integer is smaller than the second.
1 #!/usr/bin/env bash
2
3 int1=12
4 int2=13
5
6 if (( int1 < int2 )); then
7 echo lesser
8 fi
if int <=
Check if the first integer is smaller or equal to the second one.
1 #!/usr/bin/env bash
2
3 int1=12
4 int2=13
5
6 if (( int1 <= int2 )); then
7 echo less or equal
8 fi
if int >
Check if the first integer is greater than the second.
Namespaces 26
1 #!/usr/bin/env bash
2
3 int1=15
4 int2=13
5
6 if (( int1 > int2 )); then
7 echo greater
8 fi
if int >=
Check if the first integer is greater or equal to the second one.
1 #!/usr/bin/env bash
2
3 int1=12
4 int2=13
5
6 if (( int1 >= int2 )); then
7 echo greater or equal
8 fi
if string empty
Check if string is empty.
1 #!/usr/bin/env bash
2
3 str=""
4 if [ -z "$str" ]; then
5 echo "Empty string"
6 fi
7 # Empty string
1 #!/usr/bin/env bash
2
3 str="a"
4 if [ -n "$str" ]; then
5 echo "String is not empty"
6 fi
7 # String is not empty
1 #!/usr/bin/env bash
2
3 str1="hello"
4 str2="hello"
5 if [ "$str1" = "$str2" ]; then
6 echo "equal"
7 fi
8 # equal
1 #!/usr/bin/env bash
2
3 str1="hi"
4 str2="hello"
5 if [ "$str1" != "$str2" ]; then
6 echo "not equal"
7 fi
8 # not equal
if string contains
Check if string contains given substring.
Namespaces 28
1 #!/usr/bin/env bash
2
3 str="hello world!"
4
5 if [[ "$str" = *world* ]]; then
6 echo contains world
7 fi
8 # contains world
if directory exists
Check if given path is a directory.
1 #!/usr/bin/env bash
2
3 if [ -d ~/backup ]; then
4 echo "backup exists"
5 fi
if cmd exists
Read cmd
if exists
If path exists.
1 #!/usr/bin/env bash
2
3 path=~/.bashrc
4 if [ -e "$path" ]; then
5 echo exists
6 fi
if file exists
If given file exists.
Namespaces 29
1 #!/usr/bin/env bash
2
3 filepath="/path/to/file"
4
5 file if [ -f "$filepath" ]; then
6 echo file exists
7 fi
if file =
Check if two files are equal.
1 #!/usr/bin/env bash
2
3 file1=~/some_file
4 file2=~/another_file
5
6 if [ "$file1" -ef "$file2" ]; then
7 echo files are equal
8 fi
if file executable
Check if file is executable.
1 #!/usr/bin/env bash
2
3 if [ -x /bin/ls ]; then
4 echo file is executable
5 fi
if file link
If given path is a symbolic link.
Namespaces 30
1 #!/usr/bin/env bash
2
3 if [ -h /vmlinuz ]; then
4 echo symbolic link
5 fi
if file newer
Check if first file is newer than the second.
1 #!/usr/bin/env bash
2
3 file1=~/.bashrc
4 file2=~/.profile
5
6 if [ "$file1" -nt "$file2" ]; then
7 echo file1 is newer than file2
8 fi
1 #!/usr/bin/env bash
2
3 if [ -s ~/.profile ]; then
4 echo file not empty
5 fi
if file older
Check if first file is older than the second.
Namespaces 31
1 #!/usr/bin/env bash
2
3 file1=~/.bashrc
4 file2=~/.profile
5
6 if [ "$file1" -ot "$file2" ]; then
7 echo file1 is older than file2
8 fi
if file readable
Check if file is readable.
1 #!/usr/bin/env bash
2
3 if [ -r ~/.profile ]; then
4 echo file is readable
5 fi
if file writable
Check if file is writable.
1 #!/usr/bin/env bash
2
3 if [ -w ~/.profile ]; then
4 echo file is writable
5 fi
function
Contains function related operations available through func namespace. A function can return a
number between 0 to 255 which can be retrieved through $? (available as func ret val snippet).
func
Define a function to be called later. Function definition must precede its usage.
Namespaces 32
1 #!/usr/bin/env bash
2
3 function myFunction () {
4 echo "$1"
5 echo "$2"
6 }
7
8 myFunction "some argument" "another argument"
9 # some argument
10 # another argument
func args
Access to function arguments.
1 #!/usr/bin/env bash
2
3 function myFunction () {
4 echo "$@"
5 }
6
7 myFunction "some argument" "another argument"
8 # some argument another argument
1 #!/usr/bin/env bash
2
3 function myFunction () {
4 echo $#
5 }
6
7 myFunction "some argument" "another argument"
8 # 2
1 #!/usr/bin/env bash
2
3 function test () {
4 echo "$1"
5 return 25
6 }
7
8 test "return value"
9 echo "$?"
10 # return value
11 # 25
string
Contains String related operations.
string concat
concatenates two strings
1 #!/usr/bin/env bash
2
3 str1="a"
4 str2="b"
5 str="${str1}y${str2}z"
6 echo "$str" # aybz
1 #!/usr/bin/env bash
2
3 var="hello world!"
4
5 if [[ "$var" = *world* ]]; then
6 echo "substring found"
7 else
8 echo "substring NOT found"
9 fi
1 #!/usr/bin/env bash
2
3 string1='This is a string!'
4 string2='This is a string!'
5
6 if [ "$string1" = "$string2" ]; then
7 echo 'Strings are equal'
8 fi
1 #!/usr/bin/env bash
2
3 str1="shellman"
4 str2="shellmen"
5 if [ "$str1" != "$str2" ]; then
6 echo "Strings are NOT equal"
7 fi
string indexOf
Returns index of substring inside a string.
Namespaces 35
1 #!/usr/bin/env bash
2
3 myString="Hello World!"
4 temp=${myString%%"or"*} && indexOf=`echo ${myString%%"or"*} | echo ${#temp}`
5 echo $indexOf # 7
if string empty
Check if variable is an empty string.
1 #!/usr/bin/env bash
2
3 var=""
4 if [ -z "$var" ]; then
5 echo "Variable is empty string."
6 fi
7 # Variable is empty string.
1 #!/usr/bin/env bash
2
3 var="something"
4 if [ -n "$var" ]; then
5 echo "Variable is not an empty string."
6 fi
7 # Variable is not an empty string.
string length
Returns length of given string.
Namespaces 36
1 #!/usr/bin/env bash
2
3 var="abcdefg"
4 length=${#var}
5 echo "$length"
string random
Generates a random string from specified characters with desired length.
In above example random string is built up from characters A-Z, a-z and 0-9 and length of it would
be 16 characters.
string replace
Replace a substring with given string in another string.
1 #!/usr/bin/env bash
2
3 str1="Hello World!"
4 replaced=`echo -e "${str1}" | sed -e 's/World/Everyone/g'`
5 echo "$replaced" # Hello Everyone!
string reverse
Reverse given string.
1 #!/usr/bin/env bash
2
3 str1="abcd"
4 reversed=`echo -e "${str1}" | rev`
5 echo "$reversed" # dcba
string substring
Returns a substring from given string starting at index and with the length of length.
Namespaces 37
1 #!/usr/bin/env bash
2
3 str1="abcdefg"
4 substring=`echo -e "${str1:2:3}"`
5 echo "$substring" # cde
In above example we want a substring starting at index 2 to the length of 3. In abcdefg index 2 is c
(index starts at zero) and length of 3 will end up cde.
1 #!/usr/bin/env bash
2
3 frequency=`sed -E 's/(.)/\1\n/g' <<<"a!bc!def!" | grep -c "!"`
4 echo "${frequency}" # 3
string toLower
Returns lowercase of given string.
1 #!/usr/bin/env bash
2
3 str1="AbCdE"
4 toLower=`echo -e "${str1}" | tr '[:upper:]' '[:lower:]'`
5 echo "$toLower" # abcde
string toUpper
Returns uppercase of given string.
1 #!/usr/bin/env bash
2
3 str1="AbCdE"
4 toLower=`echo -e "${str1}" | tr '[:upper:]' '[:lower:]'`
5 echo "$toLower" # abcde
string trim
Removes leading and trailing whitespace(s).
Namespaces 38
1 #!/usr/bin/env bash
2
3 str1=" result "
4 result=`echo -e "${str1}" | sed -e 's/^[[:space:]]*//' | sed -e 's/[[:space:]]*$//'`
5 echo "Variable $result contains no leading and trailing space as you see"
6 # Variable result contains no leading and trailing space as you see
1 #!/usr/bin/env bash
2
3 str1=" ab c de "
4 result=`echo -e "${str1}" | tr -d '[[:space:]]'`
5 echo "All whitespaces are removed from $result as you see"
6 # All whitespaces are removed from abcde as you see
1 #!/usr/bin/env bash
2
3 str1=" whitespace on left"
4 result=`echo -e "${str1}" | sed -e 's/^[[:space:]]*//'`
5 echo "There is no $result as you see"
6 # There is no whitespace on left as you see
1 #!/usr/bin/env bash
2
3 str1="whitespace on right "
4 result=`echo -e "${str1}" | sed -e 's/[[:space:]]*$//'`
5 echo "There is no $result as you see"
6 # There is no whitespace on right as you see
array
Contains Array related operations.
array declare
Declare a literal array.
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4
5 for item in ${myArray[@]}; do
6 echo "$item"
7 done
8
9 # Alice
10 # Bob
11 # Eve
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 myArray+=("Shellman")
5
6 for item in ${myArray[@]}; do
7 echo "$item"
8 done
9
10 # Alice
11 # Bob
12 # Eve
13 # Shellman
array all
All items of array.
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 echo ${myArray[@]} # Alice Bob Eve
array at index
Returns item Nth from array (N = index).
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve" "Shellman")
4 echo ${myArray[2]} # Eve
array concat
Returns an array made of concatenation of two given arrays.
Namespaces 41
1 #!/usr/bin/env bash
2
3 array1=("Alice" "Bob" "Eve")
4 array2=("1" "2" "3")
5 newArray=("${array1[@]}" "${array2[@]}")
6 echo ${newArray[@]} # Alice Bob Eve 1 2 3
array delete
Delete entire array.
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 unset myArray
5 echo ${myArray[@]}
6 #
array delete at
Delete Nth item in array (N = index)
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 unset myArray[1]
5 echo ${myArray[@]} # Alice Eve
array filter
Filter elements of an array based on given pattern.
1 #!/usr/bin/env bash
2
3 myArray=('Alice' '22' 'Bob' '16' 'Eve')
4 filtered=(`for i in ${myArray[@]} ; do echo $i; done | grep [0-9]`)
5 echo ${filtered[@]} # 22 16
Namespaces 42
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 echo ${myArray[@]/e/} # Alice Eve
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4
5 for item in ${myArray[@]}; do
6 echo "$item"
7 done
8
9 # Alice
10 # Bob
11 # Eve
array length
Returns length of array.
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 echo ${#myArray[@]} # 3
array replace
Find and replace items in array based on regex.
Namespaces 43
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 echo ${myArray[@]//e/9} # Alic9 Bob Ev9
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve" "Shellman" "Remisa")
4 echo ${myArray[@]:1:3} # Bob Eve Shellman
In above example we are interested in 3 items of array starting at index 1 (arrays are zero base
indexed)
1 #!/usr/bin/env bash
2
3 myArray=("Alice" "Bob" "Eve")
4 myArray[1]="Shellman"
5 echo ${myArray[@]} # Alice Shellman Eve
cmd
Contains command execution related operations.
cmd
To run a command and use the returned value is named command substitution.
Namespaces 44
1 #!/usr/bin/env bash
2
3 response=`curl -s http://example.com`
4 echo "$response"
In above example using curl we retrieve the content of http://example.com and store it in response
variable (-s flag tells curl to work in silent mode).
1 #!/usr/bin/env bash
2
3 ls # this command will succeed
4
5 if [[ $? == 0 ]]; then
6 echo "command succeeded"
7 else
8 echo "command failed"
9 fi
10 # command succeeded
1 #!/usr/bin/env bash
2
3 touch /file.txt # this command will fail without sudo
4
5 if [[ $? == 0 ]]; then
6 echo "command succeeded"
7 else
8 echo "command failed"
9 fi
10 # command failed
cmd nice
Run a command with modified scheduling priority. Niceness values range from -20 (highest priority)
to 19 (lowest priority) and default value is 0.
Namespaces 45
1 #!/usr/bin/env bash
2
3 sudo nice -n 19 cp ~/file ~/tmp
In above example we are copying a file from home to tmp folder, and schedule minimum CPU time
to cp.
cmd renice
Change a running process priority. Niceness values range from -20 (highest priority) to 19 (lowest
priority) and default value is 0.
1 #!/usr/bin/env bash
2
3 for p in $(pidof "chrome"); do sudo renice -n -5 -p "$p"; done
In above example we are changing priority of chrome process and its child processes to higher than
normal.
if cmd exists
Check if a desired command exists (program is installed).
1 #!/usr/bin/env bash
2
3 if [ `command -v docker` ]; then
4 echo "docker is installed"
5 else
6 echo "docker is NOT installed"
7 fi
math
Contains Math related operations. Math functions are available under fn math ... namespace.
math % (modulus)
Given two variables, returns reminder of dividing the first variable to the second.
Namespaces 46
1 #!/usr/bin/env bash
2
3 var1=17
4 var2=5
5 reminder=$((var1 % var2))
6 echo "$reminder" # 2
1 #!/usr/bin/env bash
2
3 var1=13
4 var2=5
5 ((var1 %= var2))
6 echo "$var1" # 3
math * (multiply)
Given two variables, returns product of them.
1 #!/usr/bin/env bash
2
3 var1=3
4 var2=4
5 result=$((var1 * var2))
6 echo "$result" # 12
1 #!/usr/bin/env bash
2
3 var1=2
4 var2=3
5 ((var1 *= var2))
6 echo "$var1" # 6
Factorial
Write a function which gets a number N and prints N!.
math + (add)
Given two variables, returns sum of them.
1 #!/usr/bin/env bash
2
3 var1=2
4 var2=3
5 result=$((var1 + var2))
6 echo "$result" # 5
math ++ (increase)
Given a variables, adds one to it.
1 #!/usr/bin/env bash
2
3 var=7
4 echo $((++var)) # 8
1 #!/usr/bin/env bash
2
3 var1=2
4 var2=3
5 ((var1 += var2))
6 echo "$var1" # 5
math - (subtract)
Given two variables, returns first minus second.
1 #!/usr/bin/env bash
2
3 var1=7
4 var2=5
5 result=$((var1 - var2))
6 echo "$result" # 2
math – (decrease)
Given a variable, subtracts one from it.
1 #!/usr/bin/env bash
2
3 var=8
4 echo $((--var)) # 7
1 #!/usr/bin/env bash
2
3 var1=19
4 var2=15
5 ((var1 -= var2))
6 echo "$var1" # 4
math / (divide)
Given two variables, returns first divided by the second.
Namespaces 49
1 #!/usr/bin/env bash
2
3 var1=12
4 var2=4
5 result=$((var1 / var2))
6 echo "$result" # 3
1 #!/usr/bin/env bash
2
3 var1=12
4 var2=4
5 ((var1 /= var2))
6 echo "$var1" # 3
1 #!/usr/bin/env bash
2
3 var1="2.13"
4 var2=""2
5 result=`echo "scale=2;($var1 * $var2)" | bc`
6 echo "$result" # 4.26
Division example:
1 #!/usr/bin/env bash
2
3 var1=7
4 var2=2
5 result=`echo "scale=2;($var1 / $var2)" | bc`
6 echo "$result" # 3.50
math ^ (power)
Exponentiate base to the power.
Namespaces 50
1 #!/usr/bin/env bash
2
3 echo $((2 ** 4)) # 16
4 echo $((3 ** 3)) # 27
1 #!/usr/bin/env bash
2
3 var=2
4 result=`echo "scale=7;sqrt($var)" | bc`
5 echo "$result" # 1.4142135
math random
Generate random number between min and max
1 #!/usr/bin/env bash
2
3 echo $((5000 + RANDOM % $((65535-5000)))) # 27502
math constants
Some useful math constants.
• Ï€ = 3.14159265358979323846264338327950288
• e = 2.71828182845904523536028747135266249
• ð�›¾ = 0.57721566490153286060651209008240243
• Ω = 0.56714329040978387299996866221035554
• Ï• = 1.61803398874989484820458683436563811
color
Write text in color. color namespace contains commands to write in different foreground colors. To
write in color we use tput setaf command followed by color code. Here is color code table:
Namespaces 51
To set foreground color to red we use tput setaf 1 command and after some output we use tput
sgr0 command to set everything to default. You don’t need to memorize codes, there is a snippet for
every color. So for writing hello world in red, use color red snippet:
1 #!/usr/bin/env bash
2
3 echo `tput setaf 1`hello world`tput sgr0`
Colorful Text
Write a shell script that prints Hello World! in all 8 colors using a for loop.
format
Write text in italic, bold, dim or reverse contrast.
formated text
format bold
Write in bold.
Namespaces 52
1 #!/usr/bin/env bash
2
3 echo `tput bold`bold text`tput sgr0`
format italic
Write in italic.
1 #!/usr/bin/env bash
2
3 echo `tput sitm`italic text`tput sgr0`
format dim
Write dim text.
1 #!/usr/bin/env bash
2
3 echo `tput dim`dimmed text`tput sgr0`
format reverse
Write text in reverse contrast.
1 #!/usr/bin/env bash
2
3 echo `tput rev`reversed text`tput sgr0`
date
Contains Date related operations.
1 #!/usr/bin/env bash
2
3 dateShort=`date -I`
4 echo "$dateShort" # 2019-01-06
1 #!/usr/bin/env bash
2
3 dateUTC=`date -u`
4 echo "$dateUTC" # Sunday, January 06, 2019
1 #!/usr/bin/env bash
2
3 year=`date +%Y`
4 echo "$year" # 2019
1 #!/usr/bin/env bash
2
3 monthNumber=`date +%m`
4 echo "$monthNumber" # 01
1 #!/usr/bin/env bash
2
3 monthName=`date +%B` # %B for full month name, %b for abbreviated month name
4 echo "$monthName" # January
1 #!/usr/bin/env bash
2
3 dayOfMonth=`date +%d`
4 echo "$dayOfMonth" # 06
1 #!/usr/bin/env bash
2
3 dayOfWeek=`date +%A` # %A for full weekday name, %a for abbreviated weekday name
4 echo "$dayOfWeek" # Sunday
1 #!/usr/bin/env bash
2
3 dayOfYear=`date +%j`
4 echo "$dayOfYear" # 006
time
Contains Time related operations.
1 #!/usr/bin/env bash
2
3 timeNowLocal=`date +%R` # %R for 24 hrs
4 echo "$timeNowLocal" # 13:23
5
6 timeNowLocal=`date +%r` # %r for 12 hrs
7 echo "$timeNowLocal" # 01:23:45
1 #!/usr/bin/env bash
2
3 timeNowUTC=`date -u +%R`
4 echo "$timeNowUTC" # 12:56
1 #!/usr/bin/env bash
2
3 timeNowSecondsEpoch=`date +%s`
4 echo "$timeNowSecondsEpoch" # 1545223678
file
Contains File related operations. For logical operations about file like if a given file is writable see
logic section.
1 #!/usr/bin/env bash
2
3 rm -f ~/test.txt
file find
Find files or directories based on criteria in given path.
1 #!/usr/bin/env bash
2
3 result=`find ~ -maxdepth 5 -type f -name "*.txt"`
4 echo "$result"
In above example all files (-type f) with txt extension in home (∼) path up to 5 level of depth will
be found. To search for directories use -type d.
1 #!/usr/bin/env bash
2
3 result=`find ~ -maxdepth 1 -type f -exec grep "ls" {} +`
4 echo "$result"
In above example we will search all files in home (∼) directory up to 1 depth level, and find the ones
which contain text ls.
file read
Read contents of a file line by line.
1 #!/usr/bin/env bash
2
3 cat ~/test.txt | while read line; do
4 echo "$line"
5 done
In above example we read contents of test.txt which is in user home directory, and print it line by
line.
file write
Write to a file.
Namespaces 57
1 #!/usr/bin/env bash
2
3 lines=`docker images`
4 echo "sample header" > ~/test.txt
5 for line in ${lines}; do
6 echo "$line" >> ~/test.txt
7 done
In above example we store result of docker images command in lines variable then send sample
header text to test.txt file in home (∼) directory. Inside for loop we send each line of lines to
test.txt.
Operator > redirects output to a file and overwrite its content while operator >> will append to the
end of the file (previous contents remain there).
1 #!/usr/bin/env bash
2
3 cat >~/test.txt <<EOL
4 Header
5
6 first line
7 second line
8 EOL
1 #!/usr/bin/env bash
2
3 cat << EOL | sudo tee /test.txt
4 Header
5
6 first line
7 second line
8 EOL
1 #!/usr/bin/env bash
2
3 find ~/backup -mtime +14 | xargs rm -f
Above example removes files from ∼/backup directory which are older than two weeks.
directory
Contains directory related operations. For logical operations about directory like if a given
directory exists see logic section.
directory create
Creates a directory.
1 #!/usr/bin/env bash
2
3 mkdir -p "parent dir"/"child dir"
Nested Directories
Write a shell script to create a test directory containing 26 directories named from a to z
each containing 100 directories from 1 to 100 with a single command.
1 ── test
2 │ ├── a
3 │ │ ├── 1
4 │ │ ├── 2
5 │ . . .
6 │ . . .
7 │ │ └── 100
8 │ ├── b
9 │ │ ├── 1
10 │ │ ├── 2
11 │ . . .
12 │ . . .
13 │ │ └── 100
14 │ ├── c
15 │ . .
16 │ . .
1 #!/usr/bin/env bash
2
3 rm -rf /home/remisa/backups
In above example backups directory and all contents (files and directories) will be deleted from
/home/remisa path (home directory for user remisa).
1 #!/usr/bin/env bash
2
3 result=`find . -maxdepth 3 -type d -name "backup*"`
4 echo "$result"
Above example finds all directories (-type d) up to 3 level depth (-maxdepth 3) in the current
directory (.) where their names start with backup (-name "backup*"). To search for files use -type
f.
Namespaces 60
event
Contains event related operations available via event namespace. There are two events supported
by Shellman. EXIT and CTRL+C. Be careful about registering events multiple times. The last one you
register takes control of what happens when event fires. If you have multiple things to do, move
them all to a single function and register that function once.
event EXIT
If you need to run some commands before your script exits, you can put them in a function and call
it everywhere your script may exits. But there is an easier way to do that. Register an EXIT handler
function and it would be executed when your script execution is finished:
The trap on_exit EXIT part registers on_exit function to EXIT event. You need to register events as
soon as possible in your script. But since it needs on_exit function, you need to define that function
before registering the event.
The tput cnorm part ensures we have a visible cursor when script exits. If you are using animation
feature of Shellman don’t remove it. Anyway it is harmless and you can leave it there even if no
animation is used.
The trap on_ctrl_c SIGINT part registers on_ctrl_c function to SIGINT event. You need to register
events as soon as possible in your script. But since it needs on_ctrl_c function, you need to define
that function before registering the event.
The tput cnorm part ensures we have a visible cursor when script exits. If you are using animation
feature of Shellman don’t remove it. Anyway it is harmless and you can leave it there even if no
animation is used.
archive
Contains archive related operations like compressing and decompressing files/directories. In Linux,
tar combines files/folders into a single file without compression and mixing it with some compres-
sion utilities gives us for example archive.tar.gz. Looking at this file’s extension the tar part tells
us this file is a collection of other files/folders and gz part tells us this collection is compressed using
gzip.
1 #!/usr/bin/env bash
2
3 tar -czvf ~/archive.tar.gz ~/some-directory
In above example we are compressing and archiving a directory (some-directory) from our home
directory (denoted by ∼) into archive.tar.gz file in our home directory. This is useful for example
if we are interested to backup some-directory.
1 #!/usr/bin/env bash
2
3 tar -C ~/ -xzvf ~/archive.tar.gz
In above example we are decompressing archive.tar.gz file from our home directory into our home
directory.
1 #!/usr/bin/env bash
2
3 tar -cJf ~/archive.tar.xz ~/some-directory
In above example we are compressing and archiving a directory (some-directory) from our home
directory (denoted by ∼) into archive.tar.xz file in our home directory. This file usually is smaller
than its equivalent archive.tar.gz and the compression process is slower.
1 #!/usr/bin/env bash
2
3 tar -C ~/Documents -xf ~/archive.tar.xz
In above example we are decompressing archive.tar.xz file from our home directory into
Documents directory inside our home directory.
http
Contains HTTP related operations.
http GET
Send a GET request to specified URL.
Namespaces 63
1 #!/usr/bin/env bash
2
3 curl --request GET -sL \
4 --user-agent 'Shellman' \
5 --url 'http://example.com'
Above example sends a HTTP GET request to http://example.com with desire User Agent¹².
http DELETE
Send a DELETE request to specified URL.
1 #!/usr/bin/env bash
2
3 curl --request DELETE -sL \
4 --user-agent 'Shellman' \
5 --url 'http://example.com'
http POST
Send a POST request to specified URL.
1 #!/usr/bin/env bash
2
3 curl --request POST -sL \
4 --user-agent 'Shellman' \
5 --url 'http://example.com' \
6 --data 'key1=value1' \
7 --data 'key2=value2'
¹²https://en.wikipedia.org/wiki/User_agent
Namespaces 64
1 #!/usr/bin/env bash
2
3 curl --request POST -sL \
4 --user-agent 'Shellman' \
5 --url 'http://example.com' \
6 --form 'key=value' \
7 --form 'file=@~/image.jpg'
http header
Send http request with custom header(s).
1 #!/usr/bin/env bash
2
3 curl --request GET -sL \
4 --user-agent 'Shellman' \
5 --header 'key: value' \
6 --url 'http://example.com'
http cookie
Send http request with desired cookies.
1 #!/usr/bin/env bash
2
3 curl --request GET -sL \
4 --user-agent 'Shellman' \
5 --cookie 'key=value' \
6 --url 'http://example.com'
http download
Download from url and save to desired path.
Namespaces 65
1 #!/usr/bin/env bash
2
3 curl --request GET -sL \
4 --user-agent 'Shellman' \
5 --output '~/downloaded-file.zip' \
6 --url 'http://example.com/file.zip'
ftp
Contains FTP related operations.
ftp list
Get the list of files on the ftp server at specific path.
1 #!/usr/bin/env bash
2
3 curl ftp://remisa:1234@mydomain/backup/
ftp download
Download specified file from ftp server.
1 #!/usr/bin/env bash
2
3 curl ftp://remisa:1234@mydomain/backup/latest.zip
ftp upload
Upload specified file to ftp server at desired path.
1 #!/usr/bin/env bash
2
3 curl -T test.zip ftp://remisa:1234@mydomain/backup/
1 #!/usr/bin/env bash
2
3 curl ftp://remisa:1234@mydomain/backup/test.zip -Q "DELE test.zip"
ftp rename
Rename specified file/directory on ftp server.
1 #!/usr/bin/env bash
2
3 curl ftp://remisa:1234@mydomain/backup/ -Q "-RNFR backup/test.zip" -Q "-RNTO backup/\
4 renamed.zip"
ip
Contains ip related operations.
ip local IPs
Array of local IPs.
1 #!/usr/bin/env bash
2
3 IPS=`hostname -I`
4 echo "$IPS"
ip info
public ip information (ip, city, region, country, location, postal code, organization).
1 #!/usr/bin/env bash
2
3 echo `curl -s ipinfo.io/country`
4 # U.K
Namespaces 67
ip public
Find public ip address via different services.
• bot.whatismyipaddress.com
• ident.me
• ipecho.net/plain
• icanhazip.com
• ifconfig.me
• api.ipify.org
• ipinfo.io/ip
1 #!/usr/bin/env bash
2
3 PUBLIC_IP=`curl -s api.ipify.org`
4 echo "$PUBLIC_IP"
crypto
Contains Cryptography related operations like encryption, decryption and hashing.
Base64
This encoding is used to transform binary data into string usually to save in a file or transfer
over network.
1 #!/usr/bin/env bash
2
3 base64Encoded=`echo -n "$variableToEncode" | base64`
1 #!/usr/bin/env bash
2
3 base64Decoded=`echo -n "$variableToDecode" | base64 -d`
crypto hash
Hash variable content with desired algorithm.
1 #!/usr/bin/env bash
2
3 hash=`echo -n "$variableToHash" | md5sum | cut -f1 -d ' '`
4 echo "$hash"
Supported algorithms:
• md5
• sha
• sha1
• sha224
• sha256
• sha384
• sha512
process
Contains Process related information and operations.
process list
List all system processes.
Namespaces 69
1 #!/usr/bin/env bash
2
3 ps -A
4 # PID TTY TIME CMD
5 # 1 ? 00:00:03 systemd
6 # 2 ? 00:00:00 kthreadd
7 # 3 ? 00:00:01 ksoftirqd/0
8 # 5 ? 00:00:00 kworker/0:0H
9 # 7 ? 00:01:46 rcu_sched
10 # ...
process ID
Get process ID by its name. Many Linux commands need process id (PID).
1 #!/usr/bin/env bash
2
3 firefoxPID=`pgrep firefox`
4 echo $firefoxPID
process Kill
Kill a process by its name. kill command needs a PID (process ID) which we can find by pgrep
command via command substitution.
1 #!/usr/bin/env bash
2
3 sudo kill -9 `pgrep firefox`
In above example we find firefox PID and pass it to kill command. Here -9 is a switch of kill
command (kill signal). You can see a list of all signals by typing kill -l in terminal.
system
Contains System related information and operations.
system uptime
System uptime (hh:mm:ss).
Namespaces 70
1 #!/usr/bin/env bash
2
3 sys_uptime=`uptime | cut -d ' ' -f2`
4 echo "$sys_uptime" # 03:26:47
• MemTotal
• MemFree
• MemAvailable
• Cached
• Buffers
• Active
• Inactive
• SwapTotal
• SwapFree
• SwapCached
1 #!/usr/bin/env bash
2
3 sysMemoryMemTotal=`cat /proc/meminfo | grep 'MemTotal' | awk '{print $2}' | head -n \
4 1`
5 echo "$sysMemoryMemTotal" # total system memory in KB
1 #!/usr/bin/env bash
2
3 distroName=`lsb_release -i | awk '{print $3}'`
4 echo "$distroName"
1 #!/usr/bin/env bash
2
3 distroName=`lsb_release -r | awk '{print $2}'`
4 echo "$distroName"
1 #!/usr/bin/env bash
2
3 distroName=`lsb_release -c | awk '{print $2}'`
4 echo "$distroName"
1 #!/usr/bin/env bash
2
3 kernelName=`uname -s`
4 echo "$kernelName" # Linux
1 #!/usr/bin/env bash
2
3 kernelRelease=`uname -r`
4 echo "$kernelRelease" # 4.4.0-140-generic
1 #!/usr/bin/env bash
2
3 processorType=`uname -p`
4 echo "$processorType" # x86_64
1 #!/usr/bin/env bash
2
3 processorCount=`lscpu | grep 'CPU(s)' |awk '{print $2}' | head -n 1`
4 echo "$processorCount" # 4
1 #!/usr/bin/env bash
2
3 processorArchitecture=`lscpu | grep 'Architecture' |awk '{print $2}' | head -n 1`
4 echo "$processorArchitecture" # x86_64
1 #!/usr/bin/env bash
2
3 processorModel=`lscpu | grep 'Model name' |cut -d ' ' -f 3- | sed -e 's/^[[:space:]]\
4 *//'`
5 echo "$processorModel" # Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz
Namespaces 73
• enable
• disable
• start
• stop
• reload
• restart
• status
git
Contains git commands. You may need to install git on your system. Git is a version control system
for tracking changes of projects.
Install git:
git clone
Clone a repository to local machine.
Namespaces 74
1 #!/usr/bin/env bash
2
3 git clone https://github.com/user/repository.git
4 cd repository
1 #!/usr/bin/env bash
2
3 git clone -b develop https://github.com/user/repository.git
4 cd repository
1 #!/usr/bin/env bash
2
3 git config --list
1 #!/usr/bin/env bash
2
3 git config --global user.name "Remisa"
git commit
Commit changes.
Namespaces 75
1 #!/usr/bin/env bash
2
3 git commit -m "fixed typo"
1 #!/usr/bin/env bash
2
3 git log --all --grep='typo'
1 #!/usr/bin/env bash
2
3 git reset --soft HEAD~1 # undo last local change but don't delete them
1 #!/usr/bin/env bash
2
3 git log origin/master..HEAD
1 #!/usr/bin/env bash
2
3 git checkout -b develop
1 #!/usr/bin/env bash
2
3 git branch
1 #!/usr/bin/env bash
2
3 git push origin develop
1 #!/usr/bin/env bash
2
3 git branch -m newName
1 #!/usr/bin/env bash
2
3 git branch --delete localBranch
1 #!/usr/bin/env bash
2
3 git push origin --delete remoteBranch
1 #!/usr/bin/env bash
2
3 git checkout .
1 #!/usr/bin/env bash
2
3 git diff > patch1.patch
1 #!/usr/bin/env bash
2
3 git apply < patch1.patch
1 #!/usr/bin/env bash
2
3 git remote
1 #!/usr/bin/env bash
2
3 git remote add origin https://github.com/user/repository.git
1 #!/usr/bin/env bash
2
3 git remote set-url origin https://github.com/user/repository.git
1 #!/usr/bin/env bash
2
3 git tag
1 #!/usr/bin/env bash
2
3 git tag -a release/1.0.0 -m "1.0.0 release"
1 #!/usr/bin/env bash
2
3 git push --delete origin tagName && git push origin :tagName
1 #!/usr/bin/env bash
2
3 git push origin tagName
Namespaces 79
miscellaneous
Contains other operations not available in namespaces.
switch case
This is the switch / case you may be familiar in other languages. You can define different actions
based on switch:
1 #!/usr/bin/env bash
2
3 var=2
4
5 case "$var" in
6 1)
7 echo "case 1"
8 ;;
9 2|3)
10 echo "case 2 or 3"
11 ;;
12 *)
13 echo "default action"
14 ;;
15 esac
16 # case 2 or 3
In above example we are deciding on the value of var which here is 2. If var is 2 or 3 the second case
will be triggered. If none of cases (1, 2 or 3) are triggered, * means default and that will be triggered.
change var to 5 and output will be default action.
region
Creates a region to separate different parts of script.
1 #!/usr/bin/env bash
2
3 # >>>>>>>>>>>>>>>>>>>>>>>> variables >>>>>>>>>>>>>>>>>>>>>>>>
4 var=1
5 # <<<<<<<<<<<<<<<<<<<<<<<< variables <<<<<<<<<<<<<<<<<<<<<<<<
summary
Creates a commented summary for shell script. Use it at the top of your script.
Namespaces 80
1 #!/usr/bin/env bash
2
3 # Title: title
4 # Description: description
5 # Author: author <email>
6 # Date: yyyy-mm-dd
7 # Version: 1.0.0
8
9 # Exit codes
10 # ==========
11 # 0 no error
12 # 1 script interrupted
13 # 2 error description
Document your script error codes under Exit codes section. These are code you have used in script
when it exits due to an error (i.e. exit 5 for lack of permission to do the job).
let
let is used for mathematic operations.
1 #!/usr/bin/env bash
2
3 let a=2+3
4 echo $a # 5
5 let "a = 2 + 3"
6 echo $a # 5
7 let a++ # increase a
8 echo $a # 6
9 let "a = 2 * 3"
10 echo $a # 6
1 #!/usr/bin/env bash
2
3 var=""
4 : "${var:=default}"
5 echo "$var" # default
6
7 var="something"
8 : "${var:=default}"
9 echo "$var" # something
expr
It is and old command for doing arithmetic operations. Use $(( )) instead.
1 #!/usr/bin/env bash
2
3 result=`expr 2 \* 3`
4 echo "$result" # 6
Equivalent to:
1 #!/usr/bin/env bash
2
3 result=$((2 * 3))
4 echo "$result" # 6
ask question
Ask a question from user and receive its answer from input. It is possible to provide a default answer
to the question.
1 #!/usr/bin/env bash
2
3 read -ep "What is your name? " -i Remisa ANSWER
4 echo "$ANSWER" # print user's answer
timeout
Run a command within a time frame.
Namespaces 82
1 #!/usr/bin/env bash
2
3 timeout 5 curl -s http://example.com
4 echo "at most 5 seconds later"
service manager
Commands related to services. A service is a program which runs in background and doesn’t need
any user to login to be started (i.e. ssh).
1 #!/usr/bin/env bash
2
3 sudo systemctl restart service
sleep
Halt script for desired period in seconds s, minutes m, hours h, days d.
1 #!/usr/bin/env bash
2
3 sleep 2m
4 # halts script for 2 minutes
stopwatch
Use stopwatch to calculate script running time. There are three snippets related to stopwatch, use at
the given order:
1 #!/usr/bin/env bash
2
3 # beginning of script
4 STOPWATCH_START_TIME=$(date +%s)
5
6 # script
7 sleep 30s
8
9
10 # end of script
11 STOPWATCH_END_TIME=$(date +%s)
12
13 # print elapsed time
14 STOPWATCH_ELAPSED_TOTAL_SECONDS=$((STOPWATCH_END_TIME - STOPWATCH_START_TIME))
15 STOPWATCH_ELAPSED_MINUTES=$((STOPWATCH_ELAPSED_TOTAL_SECONDS / 60))
16 STOPWATCH_ELAPSED_SECONDS=$((STOPWATCH_ELAPSED_TOTAL_SECONDS % 60))
17 echo elapsed $STOPWATCH_ELAPSED_MINUTES minutes and $STOPWATCH_ELAPSED_SECONDS secon\
18 ds
lib
Contains a set of library functions under fn / fx namespaces. Functions can be accessed through
fn... and their usage through fx...
Math
Math related functions.
math sum
1 #!/usr/bin/env bash
2
3 function sum () {
4 local result=0
5 for item in $@; do
6 ((result += item))
7 done
8 echo $result
9 }
10
11 var1=2; var2=5; var3=4
12 result=`sum $var1 $var2 $var3`
13 echo $result
math product
1 #!/usr/bin/env bash
2
3 function product () {
4 local result=1
5 for item in $@; do
6 ((result *= item))
7 done
8 echo $result
9 }
10
11 var1=2; var2=3; var3=5
12 result=`product $var1 $var2 $var3`
13 echo $result
math average
1 #!/usr/bin/env bash
2
3 function average () {
4 local result=0
5 for item in $@; do
6 ((result += item))
7 done
8 echo $((result / $#))
9 }
10
11 var1=2; var2=3; var3=4
12 result=`average $var1 $var2 $var3`
13 echo $result
Animation
There are three related snippets in animation namespace:
Misc
Other useful functions.
banner simple
A function to print simple banners. To define the function use fn banner simple at the top of script
so later it can be called via fx banner simple:
Namespaces 86
1 #!/usr/bin/env bash
2
3 function banner_simple() {
4 # function body...
5 }
6
7 # call function
8 banner_simple "sample banner"
simple banner
banner color
A function to print colorful banners. To define the function use fn banner color at the top of script
so later it can be called via fx banner color:
1 #!/usr/bin/env bash
2
3 function banner_color() {
4 # function body...
5 }
6
7 # call function
8 banner_color yellow "sample banner"
color banner
import
Use functions defined in other shell script files inside your script. To define the function use fn
import at the top of script so later it can be called via fx import. Default folder for library files is
lib relative to calling script.
Namespaces 87
1 #!/usr/bin/env bash
2
3 function import() {
4 # function body...
5 }
6
7 import "mylib"
8
9 # Call some function from mylib.sh
In above example with import "mylib" we are importing functions defined in lib/mylib.sh.
options
A function to print multi choice questions. To define the function use fn options at the top of script
so later it can be called via fx options with question and choices. Default choice is zero based so 0
means first option, 1 means second…
1 #!/usr/bin/env bash
2
3 function chooseOption() {
4 # function body...
5 }
6
7 options=("one" "two" "three") # array of options
8 chooseOption "Choose:" 1 "${options[@]}"; choice=$? # call function
9 echo "${options[$choice]}" selected # print selected item by user
options 1
Namespaces 88
options 2
choice
progress
A dummy progress bar. You can use it as real progress bar with a little change.
1 #!/usr/bin/env bash
2
3 function progressBar() {
4 # function body...
5 }
6
7 progressBar .2 "Installing foo..."
progress
scan
1 #!/usr/bin/env bash
2
3 function scan () {
4 # function body...
5 }
6
7 # scan tcp ports 5000-10000 of localhost
8 scan tcp localhost 5000 10000
9
10 # tcp 8081 => open
11 # tcp 9000 => open
1 #!/usr/bin/env bash
2
3 # Usage: version_compare "1.2.3" "1.1.7"
4
5 function version_compare () {
6 # function body ...
7 }
Later call the function according to usage or use fx version compare | fx semver compare snippet:
version_compare function returns >, < or = as result. Here are some real example usage and the
outputs:
If the two version strings are not standard semver, version_compare function will compare each part
(separated by .) until the shorter one reaches its end. If until that point both versions look like same
it returns = as result:
¹³https://semver.org
Namespaces 90
urlencode
Encodes URL.
1 #!/usr/bin/env bash
2
3 # Usage: urlencode url
4
5 # Credit: https://unix.stackexchange.com/a/187256
6
7 function urlencode () {
8 # function body ...
9 }
10
11 # Encode the URL
12 urlencode "http://www.mysite.com/a file with spaces.html"
13
14 # Output: http%3A%2F%2Fwww.mysite.com%2Fa%20file%20with%20spaces.html
urldecode
Decodes encoded URL.
1 #!/usr/bin/env bash
2
3 # Usage: urldecode url
4
5 # Credit: https://unix.stackexchange.com/a/187256
6 function urldecode () {
7 # function body...
8 }
9
10 # Decode the URL
11 urldecode "http%3A%2F%2Fwww.mysite.com%2Fa%20file%20with%20spaces.html"
12
13 # Output: http://www.mysite.com/a file with spaces.html
Namespaces 91
animation
Why on earth one may need ASCII animation in a shell script (you can use unicode as well but it
may not work the same on all systems). To add some fun!
There are simple steps to make a beautiful animation with Shellman. You define frames and call
animate function passing it the frames array and the interval between frames in seconds. Normally
you need an animation at the end of your script, so animate function uses an infinite while loop of
course with enough sleeps.
Your frames need to have the exact same width and height. If they are different in size, fill the unused
space with spaces (no TABs).
Define animation frames at the top of your script. Here we make a simple spinner. We need frames
|, /, -, \. Use animation frame snippet:
Now add animate function to your script using fn animation animate snippet and call it with frames
array and desired delay between frames in seconds:
Namespaces 92
1 #!/usr/bin/env bash
2
3 IFS='' read -r -d '' frames[1] <<"EOF"
4 |
5 EOF
6
7 IFS='' read -r -d '' frames[2] <<"EOF"
8 /
9 EOF
10
11 IFS='' read -r -d '' frames[3] <<"EOF"
12 -
13 EOF
14
15 IFS='' read -r -d '' frames[4] <<"EOF"
16 \
17 EOF
18
19 function animate () {
20 local frames=("$@")
21 ((last_index=${#frames[@]} - 1))
22 local interval=${frames[last_index]}
23 unset frames[last_index]
24
25 # Comment out next two lines if you are using CTRL+C event handler.
26 trap 'tput cnorm; echo' EXIT
27 trap 'exit 127' HUP INT TERM
28
29 tput civis # hide cursor
30 tput sc # save cursor position
31
32 while true; do
33 for frame in "${frames[@]}"; do
34 tput rc # restore cursor position
35 echo "$frame"
36 sleep "$interval"
37 done
38 done
39 }
40
41 animate "${frames[@]}" 0.2
You can find base frames for your animations by searching the web for ascii art. For more examples
Namespaces 93
pacman
Using frames is not the best way to make animations but it is simple and straightforward. I have
made another ready to use animation function for you which gets an string and eats it up.
Use fn animation pacman snippet to insert the function into your script and use fx animation
pacman to call it:
1 function pac_man () {
2 # Function body here...
3 }
4
5 pac_man "Hello World"
¹⁴https://github.com/yousefvand/shellman/tree/master/samples/animation
Solutions
Argument Parsing
Contents of greet.sh:
Argument Parsing
1 #!/usr/bin/env bash
2
3 greeting="good night"
4 name="everyone"
5
6 # >>>>>>>>>>>>>>>>>>>>>>>> Argument parsing >>>>>>>>>>>>>>>>>>>>>>>>
7
8 POSITIONAL=()
9 while [[ $# > 0 ]]; do
10 case "$1" in
11 -m|--morning)
12 greeting="good morning"
13 shift # shift once since flags have no values
14 ;;
15 -n|--name)
16 name="$2"
17 shift 2 # shift twice to bypass switch and its value
18 ;;
19 *) # unknown flag/switch
20 POSITIONAL+=("$1")
21 shift
22 ;;
23 esac
24 done
25
26 set -- "${POSITIONAL[@]}" # restore positional params
27
28 # <<<<<<<<<<<<<<<<<<<<<<<< Argument parsing <<<<<<<<<<<<<<<<<<<<<<<<
29
30 echo "$greeting $name"
Solutions 95
Nested Directories
Contents of nested-directories.sh:
Nested Directories
1 #!/usr/bin/env bash
2
3 mkdir -p test/{a..z}/{1..100}
Colorful Text
Contents of colorful-text.sh:
Nested Directories
1 #!/usr/bin/env bash
2
3 for((i=0;i<=7;i++)); do
4 echo `tput setaf $i`Hello World!`tput sgr0`
5 done
Output:
colorful text
Factorial
Contents of factorial.sh:
Solutions 96
Factorial
1 #!/usr/bin/env bash
2
3 function fact () {
4 result=1
5 for((i=2;i<=$1;i++)); do
6 result=$((result * i))
7 done
8 echo $result
9 }
10
11 # example: 4! = 4 * 3 * 2 = 24
12 fact 4