BASH assigning command output into an array

Often find myself needing to do this but never remember how…

# flirble=(`ls -ltr ssh* | tail -3 | tr -s ' ' | cut -d ' ' -f 9` )
# echo ${flirble[*]}
ssh_host_key ssh_host_dsa_key.pub ssh_host_dsa_key
# echo ${flirble[0]}
ssh_host_key
# echo ${flirble[1]}
ssh_host_dsa_key.pub
# echo ${flirble[2]}
ssh_host_dsa_key
# echo ${flirble[3]}

# ls -ltr ssh* | tail -3
-rw-------  1 robin cm-users 539 Aug 11 12:40 ssh_host_key
-rw-r--r--  1 robin cm-users 614 Aug 11 12:40 ssh_host_dsa_key.pub
-rw-------  1 robin cm-users 668 Aug 11 12:40 ssh_host_dsa_key

This and more useful array manipulation can be found in Chapter 26 of the Advanced Bash Scripting Guide.

Sed regular expressions

The sed regular expressions are essentially the same as the grep regular expressions. They are summarized below.

^matches the beginning of the line
$matches the end of the line
.Matches any single character
(character)*match arbitrarily many occurences of (character)
(character)?Match 0 or 1 instance of (character)
[abcdef]Match any character enclosed in [] (in this instance, a b c d e or f)
ranges of characters such as [a-z] are permitted. The behaviour
of this deserves more description. See the page on grep
for more details about the syntax of lists.
[^abcdef]Match any character NOT enclosed in [] (in this instance, any character other than a b c d e or f)
(character)\{m,n\}Match m-n repetitions of (character)
(character)\{m,\}Match m or more repetitions of (character)
(character)\{,n\}Match n or less (possibly 0) repetitions of (character)
(character)\{n\}Match exactly n repetitions of (character)
\(expression\)Group operator.
\nBackreference – matches nth group
expression1\|expression2Matches expression1 or expression 2. Works with GNU sed, but this feature might not work with other forms of sed.

Setting a variable in bash if it is not defined

Update: An anonymous commenter pointed out that bash has the ability to do this in a much shorter way:

BLAH=${BLAH:-no}

Job done!, my original older way is below…

[root@sn-b02 init.d]# echo $BLAH

[root@sn-b02 init.d]# [ "${BLAH}" = "" ] && export BLAH="no"
[root@sn-b02 init.d]# echo $BLAH
no
[root@sn-b02 init.d]#

return codes

When running a command in bash it will store the return code in the special variable $?, like this:

[robin@book robin]$ ls -ld tmp
drwxr-xr-x  3 robin  robin  1024 Aug  3 11:02 tmp
[robin@book robin]$ echo $?
0
[robin@book robin]$ ls -ld bob
ls: bob: No such file or directory
[robin@book robin]$ echo $?
1
[robin@book robin]$

When running a series of commands in a pipe however it is sometimes necerssary to find the return code of an individual command in the pipe, in this case bash stores the return codes in an array names $PIPESTATUS which you can access like any other bash array. The array can only be used once however, so if you want to use it more than once store it in some other temporary array.

[robin@book robin]$ echo "tmp"  | xargs ls -ld
drwxr-xr-x  3 robin  robin  1024 Aug  3 11:02 tmp
[robin@book robin]$ echo ${PIPESTATUS[@]}
0 0
[robin@book robin]$ echo "bob"  | xargs ls -ld
ls: bob: No such file or directory
[robin@book robin]$ echo ${PIPESTATUS[@]}
0 1
[robin@book robin]$ echo "bob"  | xargs ls -ld
ls: bob: No such file or directory
[robin@book robin]$ echo ${PIPESTATUS[1]}
1
[robin@book robin]$