Differences between revisions 11 and 12
Revision 11 as of 2017-01-05 09:14:31
Size: 5285
Editor: ormaaj
Comment: 3rd person
Revision 12 as of 2022-01-11 14:21:47
Size: 5289
Editor: emanuele6
Comment: reorder bash/ksh/zsh
Deletions are marked like this. Additions are marked like this.
Line 63: Line 63:
 * bash2.04+/zsh/ksh93: `((i = 1; i <= 10; i++)); do ...`  * bash2.04+/ksh93/zsh: `for ((i = 1; i <= 10; i++)); do ...`

This page describes some common utilities that should be avoided, and what to use instead.

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.

BadUtils (last edited 2022-01-11 14:21:47 by emanuele6)