Shell Scripting
A collection of shell scripting tips & resources. Shell scripts are plain text files with an optional .sh
extension.
Base Directory
I always like to start off my scripts with these couple of lines.
#!/bin/bash
# the directory that contains this script
base=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
The first line, #!/bin/bash
specifies that the script should be run with bash, instead of a different shell.
The next line, after the comment, sets a $base
variable to the path of the script. This is useful for when the script is called from another directory and you need to change the working directory. e.g.,
# change the directory to that of this script
cd $base
Permission Denied
If permission denied, the shell script may just need to be made executable. Example: for a script named backup.sh, using chmod u+x backup.sh
will grant only the owner of the file execution permissions. For all users, replace the u
with an a
. You could also use chmod +x backup.sh
which is the same as chmod a+x backup.sh
.
chmod +x backup.sh
Then try running the script again.
./backup.sh
Detect Operating System
This sets a $sys
variable to identify the operating system the script is running on (GNU/Linux, Mac OS X, Windows NT).
if [ "$(uname)" == "Darwin" ]; then
# Mac OS X platform
sys="macOS-64"
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
# GNU/Linux platform
sys="Linux-64"
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
# 32 bits Windows NT platform
sys="Windows-32"
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
# 64 bits Windows NT platform
sys="Windows-64"
fi
Parameters
This example shows how to collect user input to act upon or optionally allow parameters on the command line.
# param 1
if [ "$1" != "" ]; then
parm1=$1
else
echo "Enter install, ls, or use"
read -p 'action: ' parm1
fi
# param 2
if [ "$2" != "" ]; then
parm2=$2
else
if [ "$2" == "install" ] || [ "$2" == "use" ]; then
echo "Enter a version, e.g., 1.0"
read -p 'ver: ' parm2
fi
fi
For example, pass parameters install
and 1.0
to the script.
./myscript.sh install 1.0
Case
If your familiar with the switch
statement, in shell scripts you can use case
. In this example, we’re checking parameters. There is a nested case
when the $1
parameter matches install
that prompts the user for confirmation before proceeding.
case "$1" in
"install")
# confirm
read -p "install version $parm2 ? [y/n] " cont
case "$cont" in
y|Y )
install
;;
* )
exit 0
;;
esac
;;
"ls")
list
;;
"use")
use
;;
esac
An entire script that is using the above examples can be inspected here.
rsync
This OS X example uses rsync to backup the Documents folder on the hard drive to an existing Documents folder on a Lexar USB stick. The --delete-before
option deletes files from the target that do not exist in the source before rsync.
if [ -d "/Volumes/Lexar/Documents" ];
then
rsync -avP "/Volumes/Macintosh HD/Users/Woz/Documents/" "/Volumes/Lexar/Documents/" --delete-before
fi
Use the --exclude
option to prevent specific files and folders from being synced. This example excludes .DS_Store
files, .git
and node_modules
folders from the backup.
if [ -d "/Volumes/Lexar/Code" ];
then
rsync -avP --exclude .DS_Store --exclude .git --exclude node_modules "/Volumes/Macintosh HD/Users/Dinesh/Code/" "/Volumes/Lexar/Code/"
fi
These shell script examples are written for Cygwin and /cygdrive/c is how the C: drive of Windows is accessed. For Cygwin, the rsync package would need to be installed. On OS X and Linux, rsync is usually included in the system install.
This example uses rsync to backup an existing file to a server share.
if [ -f /cygdrive/c/Users/Gilfoyle/Dropbox/Private/Hooli.xlsx ];
then
rsync -avP /cygdrive/c/Users/Gilfoyle/Dropbox/Private/Hooli.xlsx //FILESERVER/share/Hooli.xlsx
fi
This example uses rsync to backup an existing Private Dropbox folder to a server share.
if [ -d /cygdrive/c/Users/Gilfoyle/Dropbox/Private ];
then
rsync -avP /cygdrive/c/Users/Gilfoyle/Dropbox/Private/ //FILESERVER/share/
fi
tar
This example checks for the existing source directory and creates a compressed archive in the current directory with a datetime string included in the filename. The source directory and its contents will be added to the archive while exluding node_modules .git and sass.cache
if [ -d /cygdrive/c/Users/Dinesh/Code ];
then
now=$(date +"%Y-%m-%dT%H%M%S")
tar -zcvf code_$now.tar.gz --exclude .git --exclude node_modules --exclude sass.cache /cygdrive/c/Users/Dinesh/Code
fi
dos2unix
Find all files inside the current directory and execute dos2unix on each converting DOS format line breaks (CRLF) to Unix format (LF).
find . -type f -exec dos2unix {} \;
unix2dos
Find all files inside the current directory and execute unix2dos on each converting Unix format line breaks (LF) to DOS format (CRLF).
find . -type f -exec unix2dos {} \;