Classic Shell Scripting - Arnold Robbins [210]
termnames=(gl35a t2000 s531 vt99)
echo 'Select your terminal type:'
PS3='terminal? '
select term in \
'Givalt GL35a' \
'Tsoris T-2000' \
'Shande 531' \
'Vey VT99'
do
if [[ -n $term ]]; then
TERM=${termnames[REPLY-1]}
echo "TERM is $TERM"
export TERM
break
fi
done
This code sets up the array termnames so that ${termnames[0]} is gl35a, ${termnames[1]} is t2000, etc. The line TERM=${termnames[REPLY-1]} essentially replaces the entire case construct by using REPLY to index the array.
Notice that both shells know to interpret the text in an array index as an arithmetic expression, as if it were enclosed in $(( and )), which in turn means that the variable need not be preceded by a dollar sign ($). We have to subtract 1 from the value of REPLY because array indices start at 0, whereas select menu item numbers start at 1.
Miscellaneous Extensions
Here is another laundry list, this time of small extensions to the POSIX shell supported by both bash and ksh93:
Additional tilde expansions
POSIX specifies plain ~ as being equivalent to $HOME and ~ user as being user's home directory. Both shells allow you to use ~+ as short for $PWD (the current working directory) and ~- as short for $OLDPWD (the previous working directory).
Arithmetic commands
POSIX specifies the $((...)) notation for arithmetic expansion, and doesn't provide any other mechanism for arithmetic operations. However, both shells provide two notations for doing arithmetic directly, not as an expansion:
let "x = 5 + y" The let command, requires quoting
((x = 5 + y)) No leading $, automatic quoting inside double parentheses
It's not clear why POSIX standardizes only arithmetic expansion. Perhaps it's because you can achieve essentially the same affect by using the : (do-nothing) command and arithmetic expansion:
: $((x = 5 + y)) Almost the same as let or ((...))
x=$((5 + y)) Similar, no spaces allowed around the =
One difference is that let and ((...)) have an exit status: zero for a true value and one for a false value. This lets you use them in if and while statements:
while ((x != 42))
do
... whatever ...
done
Arithmetic for loop
Both shells support the arithmetic for loop, which is similar to the for loop in awk, C, and C++. It looks like this:
for ((init; condition; increment))
do
loop body
done
Each one of init, condition, and increment can be shell arithmetic expressions, exactly the same as would appear inside $((...)). The use of ((...)) in the for loop is purposely similar to the arithmetic evaluation syntax.
Use the arithmetic for loop when you need to do something a fixed number of times:
for ((i = 1; i <= limit; i += 1))
do
whatever needs doing
done
Additional arithmetic operators
POSIX specifies the list of operators that are allowed inside arithmetic expansion with $((...)). Both shells support additional operators, to provide full compatibility with C. In particular, both allow ++ and -- to increment and decrement by one. Both the prefix and postfix forms are allowed. (According to POSIX, ++ and -- are optional.) Both shells accept the comma operator, which lets you perform multiple operations in one expression. Also, as an extension over and above C, both shells accept ** for exponentiation. The full list of operators is provided in Table 14-5.
Optional matching parentheses for case statements
The $(...) syntax for command substitution (see Section 7.6) is standardized by POSIX. It was introduced in ksh88 and is also supported in bash. ksh88 had a problem with case statements inside $(...). In particular, the closing right parenthesis used for each case pattern could terminate the entire command substitution. To get around this, ksh88 required that case patterns