if you are on busybox with ash none of this is helping (except shellcheck which is great).
if you are on busybox with ash none of this is helping (except shellcheck which is great).
Python (the language with the most community traction to replace bash for scripts) is a royal pain to use for this without libraries that are present in no default system, and even with those it often ends up being more verbose than it should.
maybe I was not clear - nothing against shell-scripting but doing some weird dancing like in the article is imho useless, also depending on bash is a stupid idea imho.
posix sh + shellcheck is all you need. if you can't solve your problem in posix sh rethink your code / approach and simplify until it will work.
I've used this page successfully as reference for portable syntax:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3...
Some sections on features I use heavily:
- Parameter Expansion (specifically :-, %, %%, #, ##)
- Special Parameters (specifically "$@", $#, $?)
- set --, this lets you set the $1, $2, etc. variables. I use this with "$@" for arrays, primarily for building command strings.
Here's an small shell script demonstrating some of them:
#!/bin/sh
# err function
err() { echo "$1" >&2; exit 1; }
# init variables
unset src
unset dst
dry_run=false
# get arguments
while [ $# -gt 0 ]; do
case "$1" in
-d|--dry-run) dry_run=true ;;
--) shift; break ;;
-*) err "unknown option: $1" ;;
*)
if [ -z "$src" ]; then src="$1"
elif [ -z "$dst" ]; then dst="$1"
else err "unexpected argument: $1"
fi
;;
esac
shift
done
# sanity checks
## TODO: print usage
if [ -z "$src" ]; then err "source not specified"; fi
if [ ! -d "$src" ]; then err "source does not exist"; fi
if [ ! -r "$src" ]; then err "cannot read source directory"; fi
if [ -z "$dst" ]; then err "destination not specified"; fi
if ! rsync --version >/dev/null 2>&1; then
err "missing rsync(1)"
fi
# build rsync command
set -- rsync -aq "$src" "$dst"
# log command
echo "copying $src to $dst"
echo " $@"
if ! $dry_run; then
if "$@"; then
echo "success"
else
# rsync will have printed an error message
err "rsync exited with error code $?"
fi
else
echo "dry run; not executing"
fi
Also be sure to read the man page for test (the [ command).I agree that python is a pain. It's too low level for any task.
Doesn't matter if it's better or worse, it isn't omnipresent.
python is about 4.5MB and Lua is about 200K, both run on top of a shell anyways, and need some packages to be fully useful.
To be fair adding 200KB Lua (no luarocks etc) on top of a shell is useful sometimes on embedded system, but I rarely need that.
If you're going to be distributing shell scripts, it's probably a good idea to test them on a handful of common shells anyway. If portability between shells isn't something you're worried about, it's exactly as reasonable to ask users to install bash as it is to ask them to install mksh or zsh (or even python or lua or whatever) anyway. If you're most comfortable with bash, just use bash!
But for the love of god and all that is holy, please don't write csh scripts ;)