This page describes some common utilities that should be avoided, and what to use instead.
Contents
pidof
pidof is a strange program. On some systems it's a symlink to the killall5 program - part of the sysvinit package. It is used by init to send signals to all processes (e.g. to kill them during shutdown). If invoked as pidof, it returns the pid of the given program. pidof Is highly nonstandard, yet seen frequently in examples likely due to its intuitive name.
Alternatives
The pgrep utility - part of the procps suite. pgrep returns pids of processes matching the given regex, and is very preferable to grepping ps output. While also nonstandard, pgrep is widely available (if not installed by default) and the utilities are generally good quality. procps also includes a pidof implementation, so if there's a choice it's better to just install it and avoid the sysvinit version.
Process "names" are NOT a reliable way to work with processes! Searching by name should only be done interactively in a pinch when the need to follow a process couldn't be anticipated. Never do it in scripts or programs! See: ProcessManagement.
killall
On some systems (Linux-based ones, usually) this may try to send a signal to a bunch of processes based on their names (a dodgy practice at best -- see above). On others (Unix System V-based ones) it will try to kill every running process regardless of name. In either case, it's nonstandard.
Alternatives
Use pkill, also from procps. But see ProcessManagement for proper ways to manage processes.
which
which is a non-standard command, though commonly available. It is useless and redundant, both in scripts and interactive shells. Some common bad usages:
# Wrong GREP=`which grep` ... $GREP rm logfile
What happens here is that which searches for grep in the PATH environment variable, and outputs the path to the first grep it finds. If it doesn't find it, it might output nothing, an error to stdout, or an error to stderr. It may or may not return a non-zero exit status. If the which command outputs nothing when the command is not found, the above may result in the GREP variable being empty, in which case $GREP rm logfile expands into rm logfile, which does something other than search for the string "rm" in logfile.
# Right grep rm logfile
Guess what, bash can also search through PATH for commands, in addition to first looking for aliases, functions or builtins by that name. So the which command added nothing useful, only bugs.
The other common use of which is to check if a command exists. The shell can do this already (for example using type), and better, so why use an inferior, external command?
Alternatives
The builtins type, command and hash. See BashFAQ/081
xargs
xargs is standard and moderately useful, but it has a number of unfortunate legacy warts which makes it somewhat cumbersome and sometimes outright dangerous to use. Consider replacing it with a more modern alternative.
Specifically, xargs splits its input on any kind of whitespace, and parses quotes. A filename with spaces or quotes in its name will not be preserved and passed along correctly.
GNU xargs has a -0 option that suppresses those misfeatures, but only for NUL-delimited input streams (e.g. those produced by GNU find with the -print0 option). But it's much cleaner and simpler to just use find ... -exec foo {} + and skip xargs altogether, especially if parallelism is unimportant.
Alternatives
See UsingFind for better ways to execute a command with a whole bunch of files as arguments.
Another alternative is GNU Parallel (which ironically had some odd behaviors to explain in its earlier versions...).
expr
Pure legacy program. Has no real use in a Bash script. The Bourne shell could not do arithmetic, so you had to call this external utility to increment a loop counter. Even POSIX sh can do that much.
Alternatives
For arithmetic, use $((...)), ((...)) or let. For various string manipulations and tests, see FAQ 100 or FAQ 31.
seq
seq is non-standard and almost always used where brace expansion, shell arithmetic, or some other native shell feature would be more appropriate. Don't use seq in a command substitution to produce numbers as arguments - e.g. in a for loop. If a stream of digits produced on stdout is actually needed for some other reason then seq may be an efficient choice especially if the output will be large enough to offset the cost of forking an external utility, it's just not very portable. Don't use $(seq).
Alternatives
bash2.04+/ksh93/zsh: for ((i = 1; i <= 10; i++)); do ...
bash3.0+/ksh93/zsh: for i in {1..10}; do ...
POSIX: i=0; while [ "$i" -lt 10 ]; do ...; i=$((i + 1)); done
See also conditional loops.