Bash tips¶
How to do certain common-but-difficult things correctly. Plus reminders of commands I routinely forget.
General¶
Use printf, not echo¶
POSIX recommends against echo
because it has serious limitations, including platform-specific behavior, inconsistent \n
handling, and an n-ary argument list not terminated by --
.
How to get a script’s own directory¶
Doing this correctly is a bit tricky.
Note these features:
--
is needed because, outside a script,$0
is (e.g.)-z
, whichreadlink
assumes is an option and errors with an unhelpful message.- The
|| exit $?
after thereadlink
is needed to exit the subshell immediately. Otherwise,dirname
is called but with no stdin, causing it to return.
. - The outer
|| exit $?
catches any unlikely nonzero exits fromdirname
.
A tiny caveat: This will fail on a fraction of outrageously strange paths. In particular, it will break on a path that contains a newline – a character that ext4 and btrfs support and that Linux will technically accept. But this would cause more serious problems, and if you’re naming files like this, stop.
This function seems to work in Bash 5.2 on Ubuntu 25.04 and macOS 24.
get_type() {
local v re
v="$(type "$1" || true)"
re="[[:space:]]is[[:space:]]an?[[:space:]]"
if [[ ! "$v" =~ $re ]]; then
echo command
return
fi
case "$v" in
*alias* )
echo alias
;;
*function* )
echo 'function'
;;
*builtin* )
echo builtin
;;
*reserved* )
echo keyword
;;
*is* )
echo command
;;
*not* )
echo undefined
;;
*)
echo unknown
;;
esac
}
Miscellaneous notes¶
-
man builtin
covers all builtins for your shell. -
my_func() { }
fails in Bash but not ZSH. Bash requires functions to have contents, so usemy_func() { true }
. - For security, be extremely careful with
env
,export
, anddeclare
. Calling them without arguments may leak secrets.