Neat Bash Tricks

I’ve been writing lots of bash scripts lately, so I thought it would be a good idea to document a few of the little tricks I’ve been using.

First off, to make a script that has to be executed in bash:

#!/bin/bash

if [ ! "$BASH_VERSION" ] ; then
  echo "Please do not use sh to run this script ($0), just execute it directly" 1>&2
  exit 1
fi

This was needed for a script that makes uses of Bash syntax for for loop and some basic math, and I had a user reporting errors when they tried to do sh script.sh. sh ignores the opening #!/bin/bash line and tries to execute the script directly, and fails when it hits those lines.

Then, to make a script that has to be sourced in the global environment (to set environment variables like PATH and LD_LIBRARY_PATH for the user).

#!/bin/bash

if [[ "$(basename "$0")" == "script.sh" ]]; then
  echo "ERROR: Don't run $0, source it" >&2
  exit 1
fi

replace script.sh with the name of the actual file.

Then, to URL Encode a parameter in bash (I used this to encode a user provided git password into the url), use this function:

rawurlencode() {

  local string="${1}"
  local strlen=${#string}
  local encoded=""

  for (( pos=0 ; pos
    c=${string:$pos:1}
    case "$c" in
      [-_.~a-zA-Z0-9] ) o="${c}" ;;
      * )               printf -v o '%%%02x' "'$c"
    esac
    encoded+="${o}"
  done
  echo "${encoded}"    # You can either set a return variable (FASTER)
  REPLY="${encoded}"   #+or echo the result (EASIER)... or both... :p
}

Then you can use it like so:

echo Enter your GitHub username:

read GIT_USER

echo Enter your GitHub Password:
read GIT_PASSWORD

GIT_AUTH=$( rawurlencode "${GIT_USER}" ):$( rawurlencode "${GIT_PASSWORD}" )

git clone http://${GIT_AUTH}@github.com/user/repo

yeah yeah, I know.. SSH keys are better… tell it to the users, not me

Finally, using getopt. It’s a big tool, but the basics of using it:

USE_SSH=0
AUTOMATED=0
BUILD_WIDTH=1

while getopts "aj:s" o; do
    case "${o}" in
        s)
            USE_SSH=1
            ;;
        a)
            AUTOMATED=1
            ;;
        j)
            BUILD_WIDTH=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

Important bits:

  • the getopts line: Include each character recognized as a flag, and following it with a : if it requires an argument.
  • Then include a case for each one in the big switch.. use $(OPTARG) to get the argument, if it’s needed.

Makes argument parsing simple in bash scripts simple… Also define a usage function to spew out the supported options, and you’re golden.


comments powered by Disqus