Bash

Resources

The Linux Documentation Project

BashFAQ

Storing command output/status in variables:

# Capture output

OUTPUT=$(command)
STATUS=$?
# Branch on status

if command
then
    echo "success"
fi

if OUTPUT=$(command)
then
    echo "success - ${OUTPUT}"
fi
# Pipelines

set -o pipefail
find /invalidpath | wc -l  # Returns last non-zero subcommand status

Reading files line-by-line:

{
    while IFS= read -r LINE
    do
        printf '%s\n' "${LINE}"
    done

    # Handle edge case when last line isn't newline terminated
    # `read` consumes LINE but returns false,
    # Handle leftover partial line

    if [[ -n ${LINE} ]]
    then
        printf '%s\n' "${LINE}"
    fi
}

Using ‘find’:

while IFS= read -r -d '' LINE
do
    printf '%s\n' "${LINE}"
done < <(find -name "$PATTERN" -print0)

Tests

Variable is set:

if [[ -z ${VARIABLE+notset} ]]
then
    # VARIABLE is not set
fi

if [[ ! -z ${VARIABLE+notset} ]]
    # VARIALBE is set
fi

Variable has non-zero length:

if [[ -n ${VARIABLE} ]]
then
    # VARIABLE has non-zero length
fi

if [[ -z ${VARIABLE} ]]
then
    # VARIABLE either has zero length or is unset
fi

Argument count:

if [[ $# -eq 1 ]]
then
    # 1 argument passed
fi

if [[ $# -gt 1 ]]
then
    # More than 1 argument passed
fi

Expansion

Order

Expansion type

Example

1

Brace expansion

echo foo{A,B,C}bar

2

Tilde expansion

ls ~/.vimrc

3

Parameter expansion

echo ${PATH}

4

Command substitution

readlink -f $(which python)

5

Arithmetic expansion

echo $(( 365 * 24 ))

6

Process substitution

diff <(date) <(sleep 1; date)

7

Word splitting

args () {
    printf "%d arguments:" "$#"
    printf " <%s>" "$@"
    echo
}
args hello world "how are you?"
VAR="This is a variable"
args $VAR
args "$VAR"

8

Filename expansion

ls *.pyc

Redirection

From

To

Syntax

stdout

command.stdout

>command.stdout

stderr

command.stderr

2>command.stderr

stdout

stderr

1>&2

stderr

stdout

2>&1

stdout & stderr

command.out

&>command.out

stdout & stderr

/dev/null & stdout

2>&1 >/dev/null

Builtins

command

Run command ignoring any shell functions. Only shell builtin commands or commands found by searching the PATH are executed

help

Online help for builtin commands.

read

Read from stdin or file descriptor. (See also: Bash Hackers Wiki)

Special Variables

$#

Number of positional parameters.

$*

Positional parameters, starting from position 1.

  • When the expansion is not within double quotes, each positional parameter expands to a separate word.

  • When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable.

$@

Positional parameters, starting from position 1.

  • In contexts where word splitting is performed, this expands each positional parameter to a separate word; if not within double quotes, these words are subject to word splitting.

  • In contexts where word splitting is not performed, this expands to a single word with each positional parameter separated by a space.

When the expansion occurs within double quotes, and word splitting is performed, each parameter expands to a separate word.

$?

Exit status of the most recently executed foreground pipeline.

$-

Current option flags as specified upon invocation, by the set builtin command, or those set by the shell itself (such as the -i option).

$$

Process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell.

$!

Process ID of the job most recently placed into the background, whether executed as an asynchronous command or using the bg builtin.

$0

Name of the shell or shell script.

$_

At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list. Subsequently, expands to the last argument to the previous simple command executed in the foreground, after expansion.

Also set to the full pathname used to invoke each command executed and placed in the environment exported to that command.

Aliases

Advanced Bash-Scripting Guide: Aliases

In a script, aliases have very limited usefulness. It would be nice if aliases could assume some of the functionality of the C preprocessor, such as macro expansion, but unfortunately Bash does not expand arguments within the alias body. Moreover, a script fails to expand an alias itself within “compound constructs,” such as if/then statements, loops, and functions. An added limitation is that an alias will not expand recursively. Almost invariably, whatever we would like an alias to do could be accomplished much more effectively with a function.

StackOverflow: Watch command alias expansion

Aliases are only expanded as the first argument, or after another alias with a trailing space on the end of the command. From bash’s help alias:

A trailing space in VALUE causes the next word to be checked for alias substitution when the alias is expanded.

To do this, try the following:

alias watch='watch '
alias ll='ls -l --color=tty'
watch ll