Shell Expansions

Table of Contents

Special Parameters ($#, $$, $*, $@, …) reference

$*
positional parameters
$@
positional parameters
$#
number of positional parameters
$?
exit status of the most recently executed foreground pipeline.
$-
current option flags as specified upon invocation, by the set
$$
process ID of the shell
$!
process ID of the job most recently placed into the background
$0
name of the shell or shell script.
$_
?

Arithmetic Expansion($(( expression ))) reference

$(( expression ))

Brace Expansion(a{d,c,b}e, …) reference

$ echo a{d,c,b}e
ade ace abe

$ mkdir /usr/local/src/bash/{old,new,dist,bugs}
$ chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

Filename Expansion(or blobs) reference

*
Matches any string, including the null string.
**
Matches all files and zero or more directories and subdirectories.
**/
Matches all subdirectories.
?
Matches any single character.
[...]
Matches any one of the enclosed characters.

History Expansion(!ps, …) reference

$ history
1 tar cvf etc.tar /etc/
2 cp /etc/passwd /backup
3 ps -ef | grep http
4 service sshd restart
5 /usr/local/apache2/bin/apachectl restart

$ !4  # 4
service sshd restart

$ !-2  # 2 commands back
service sshd restart

$ !!   # last (1 command back)
$ !-1

$ !ps  # command that starts with 'ps'
ps -ef | grep http

$ !?apache  # command that contains 'apache'
/usr/local/apache2/bin/apachectl restart


$ ls /etc/cron.daily/logrotate

$ ^ls^cat^  # replace 'ls' with 'cat'
cat /etc/cron.daily/logrotate

$ cp /etc/passwd /backup

$ ls -l !cp:^  # first argument
ls -l /etc/passwd

$ cp /etc/passwd /backup

$ ls -l !cp:$  # last argument
ls -l /backup

$ ls -l !!:$  # last argument of last command
$ ls -l !$    # equivalent to above

$ ls -l !!:2  # second
$ ls -l !!:*  # all

$ !!:s/ls -l/cat/  # substitution

$ cp /etc/password /backup/password.bak
$ !!:gs/password/passwd/  # global substitution
cp /etc/passwd /backup/passwd.bak

$ ls -l !!:$:p  # print without executing it

Shell Parameter Expansion(${parameter:-word}, …) reference

unset and null testing expansions

if not parameter:
  word
else:
  parameter
${parameter:=word}
if not parameter:
  parameter = word
  parameter
${parameter:?word}
if not parameter:
  stderr.write(word)
  exit
else:
  parameter
${parameter:+word}
if not parameter:
  parameter
else:
  word
non : versions (like ${parameter-word})

Tests only whether parameter is unset, but not null

word

Can be a variable like $(parameter:-$foo}

unset FOO
echo ${FOO-bar}   # bar
echo ${FOO?bar}   # (cause an error)
echo ${FOO+bar}   # (unset value of FOO)
echo ${FOO:-bar}  # bar
echo ${FOO:?bar}  # (cause an error)
echo ${FOO:+bar}  # (unset value of FOO)
unset FOO
echo ${FOO=bar}   # bar
echo ${FOO}       # bar
unset FOO
echo ${FOO:=bar}  # bar
echo ${FOO}       # bar


FOO=
echo ${FOO-bar}   # (null value of FOO)
echo ${FOO?bar}   # (null value of FOO)
echo ${FOO+bar}   # bar
echo ${FOO:-bar}  # bar
echo ${FOO:?bar}  # (cause an error)
echo ${FOO:+bar}  # (null value of FOO)
FOO=
echo ${FOO=bar}   # (null value of FOO)
echo ${FOO}       # (null value of FOO)
FOO=
echo ${FOO:=bar}  # bar
echo ${FOO}       # bar


FOO=foo
echo ${FOO-bar}   # foo
echo ${FOO?bar}   # foo
echo ${FOO+bar}   # bar
echo ${FOO:-bar}  # foo
echo ${FOO:?bar}  # foo
echo ${FOO:+bar}  # bar
FOO=foo
echo ${FOO=bar}   # foo
echo ${FOO}       # foo
FOO=foo
echo ${FOO:=bar}  # foo
echo ${FOO}       # foo

offset and length

${parameter:offset}        # parameter[offset:]
${parameter:offset:length} # parameter[offset:offset+length]
# 1. A normal variable
$ string=01234567890abcdefgh
$ echo ${string:7}
7890abcdefgh
$ echo ${string:7:2}
78

# If length evaluates to a number less than zero,
# it is interpreted as an offset in characters from the end of the value of parameter
# rather than a number of characters
$ echo ${string:7:-2}
7890abcdef

# offset can be negative, but must be separated from the colon by at least one space
# to avoid being confused with the ‘:-’ expansion.
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:-2}
bcdef

# 2. Arguments
$ set -- 01234567890abcdefgh
$ echo ${1:7}
7890abcdefgh

# 3. Array
$ array[0]=01234567890abcdefgh
$ echo ${array[0]:7}
7890abcdefgh

begining and trailing match deletion (#, %)

# If the pattern matches the **beginning** of the expanded value of parameter,
${parameter#word}  # the shortest matching pattern **deleted**
${parameter##word} # the longest matching pattern **deleted**

# If the pattern matches a **trailing portion** of the expanded value of parameter,
${parameter%word}  # the shortest matching pattern **deleted**
${parameter%%word} # the longest matching pattern **deleted**

replace

${parameter/pattern/string}  # the longest match of pattern against its value is replaced with string.
${parameter//pattern/string} # all matches of pattern are replaced with string.
${parameter/#pattern/string} # matches at the beginning of the expanded value of parameter.
${parameter/%pattern/string} # matches at the end of the expanded value of parameter.
${parameter/pattern/}        # deleted
${parameter/pattern}         # same as above
export FOO='a.b.c.d'
echo "${FOO/[.]/-}"
echo "${FOO//[.]/-}"
| a-b.c.d |
| a-b-c-d |

Others

# This expansion modifies the case of alphabetic characters in parameter.
${parameter^pattern}
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}

# The expansion is either a transformation of the value of parameter or information about parameter itself, depending on the value of operator.
# Operators: Q, E, P, A, a
${parameter@operator}

$@ or $* discussion

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3