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.
Force Execution
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.
URL Encoding Arguments
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<strlen ; pos++ )); do 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*
GetOpt
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.