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 {} \;

Resources

comments powered by Disqus