bash(1)
Keys
ctrl + r # search history
alt/esc + . # last argument of previous command
ctrl + l # clear screen
ctrl + a # move to beginning of line
ctrl + e # move to end of line
ctrl + w # delete word before cursor
ctrl + u # delete from cursor to beginning of line
ctrl + k # delete from cursor to end of line
ctrl + y # paste deleted text
Paratheses
() # run in subshell
(()) # arithmetic expansion
[] # test command, check file attributes, numeric comparison
[[]] # extended test command, more powerful than [], string comparison
Expansion
Generator
# generate two names
cp file{,.bak}
# generate sequence from n to m
{n..m}
# generate sequence from n to m step by s
{n..m..s}
# expand cartesian product
{a,b}{c,d}
!, ^ and -
!! # last command
!$ # last argument of last command
!* # all arguments of last command
^foo^bar # replace first occurence of foo with bar in last command
cd - # change to previous working directory
$
$? # exit status of last command
$$ # PID of current shell
$! # PID of last background command
$# # number of arguments
$@ # all arguments
$* # all arguments as single string
Parameter
# default value
bar=${foo:-some_val} # if $foo set, then bar=$foo else bar=some_val
# check param set
bar=${foo:?msg} # if $foo set, then bar=$foo else exit and print msg
# indirect
FOO=foo
BAR=FOO
bar=${!BAR} # deref value of BAR -> bar=$FOO
# prefix
${foo#prefix} # remove prefix when expanding $foo
# suffix
${foo%suffix} # remove suffix when expanding $foo
# substitute
${foo/pattern/string} # replace pattern with string when expanding foo
# pattern starts with
# '/' replace all occurences of pattern
# '#' pattern match at beginning
# '%' pattern match at end
# set programmatically with printf builtin
printf -v "VAR1" "abc"
NAME=VAR2
printf -v "$NAME" "%s" "def"
Note:
prefix
/suffix
/pattern
are expanded as pathnames.
Pathname
* match any string
? match any single char
\\ match backslash
[abc] match any char of 'a' 'b' 'c'
[a-z] match any char between 'a' - 'z'
[^ab] negate, match all not 'a' 'b'
[:class:] match any char in class, available:
alnum,alpha,ascii,blank,cntrl,digit,graph,lower,
print,punct,space,upper,word,xdigit
With extglob
shell option enabled it is possible to have more powerful
patterns. In the following pattern-list
is one ore more patterns separated
by |
char.
?(pattern-list) matches zero or one occurrence of the given patterns
*(pattern-list) matches zero or more occurrences of the given patterns
+(pattern-list) matches one or more occurrences of the given patterns
@(pattern-list) matches one of the given patterns
!(pattern-list) matches anything except one of the given patterns
Note:
shopt -s extglob
/shopt -u extglob
to enable/disableextglob
option.
I/O redirection
Note: The trick with bash I/O redirection is to interpret from left-to-right.
# stdout & stderr to file
command >file 2>&1
# equivalent
command &>file
# stderr to stdout & stdout to file
command 2>&1 >file
The article Bash One-Liners Explained, Part III: All about redirections contains some nice visualization to explain bash redirections.
Explanation
j>&i
Duplicate fd i
to fd j
, making j
a copy of i
. See [dup2(2)][dup2].
Example:
command 2>&1 >file
- duplicate
fd 1
tofd 2
, effectively redirectingstderr
tostdout
- redirect
stdout
tofile
Process substitution ([ref][psub])
Process substitution allows to redirect the stdout of multiple processes at once.
vim -d <(grep foo bar) <(grep foo moose)
Command grouping
Execute commands in a group with or without subshell. Can be used to easily redirect stdout/stderr of all commands in the group into one file.
# Group commands without subshell.
v=abc ; { v=foo; echo $v; } ; echo $v
# foo
# foo
# Group commands with subshell.
v=abc ; ( v=foo; echo $v; ) ; echo $v
# foo
# abc
Trap Handling
trap "<CMDs>" <SIG>/EXIT
# Show current trap handler.
trap -p
# List signal names.
trap -l
Example: Run handler only on error exit
trap 'test $? -ne 0 && echo "run exit trap"' EXIT
# -> no print
exit 0
# -> print
exit 1
Example: Mutex in shell script
For example if a script is triggered in unsynchronized, we may want to ensure that a single script instance runs.
# open file=LOCK with fd=100
exec 100>LOCK
# take exclusive lock, wait maximal for 3600s
flock -w 3600 -x 100 || { echo "flock timeout"; exit 1; }
# eg automatically release lock when script exits
trap "flock -u 100" EXIT
Argument parsing with getopts
The getopts
builtin uses following global variables:
OPTARG
, value of last option argumentOPTIND
, index of the next argument to process (user must reset)OPTERR
, display errors if set to1
getopts <optstring> <param> [<args>]
<optstring>
specifies the names of supported options, egf:c
f:
means-f
option with an argumentc
means-c
option without an argument
<param>
specifies a variable name whichgetopts
fills with the last parsed option argument<args>
optionally specify argument string to parse, by defaultgetopts
parses$@
Example
#!/bin/bash
function parse_args() {
while getopts "f:c" PARAM; do
case $PARAM in
f) echo "GOT -f $OPTARG";;
c) echo "GOT -c";;
*) echo "ERR: print usage"; exit 1;;
esac
done
# users responsibility to reset OPTIND
OPTIND=1
}
parse_args -f xxx -c
parse_args -f yyy
Regular Expressions
Bash supports regular expression matching with the binary operator =~
.
The match results can be accessed via the $BASH_REMATCH
variable:
${BASH_REMATCH[0]}
contains the full match${BASH_REMATCH[1]}
contains match of the first capture group
INPUT='title foo : 1234'
REGEX='^title (.+) : ([0-9]+)$'
if [[ $INPUT =~ $REGEX ]]; then
echo "${BASH_REMATCH[0]}" # title foo : 1234
echo "${BASH_REMATCH[1]}" # foo
echo "${BASH_REMATCH[2]}" # 1234
fi
Caution: When specifying a
regex
in the[[ ]]
block directly, quotes will be treated as part of the pattern.[[ $INPUT =~ "foo" ]]
will match against"foo"
notfoo
!