factorial() { local N; eval let N=1 N*={1..$1}; echo "$N"; }
Using let
, this takes advantage of its mathematical functions and argument-based variable assignments to serially overwrite the last known value of N
with the product of N
and the next integer generated by the expansion of {1..$1}
into a list of incremental numbers.
Since the sequence expression {x..y}
only works with literal values, {1..$1}
would not be expanded to a sequence of numbers. For example when $1
is 3, then {1..$1}
expands to {1..3}
instead of the sequence 1 2 3. This is the reason we use eval
, so that in this example evaluating the expression {1..3}
expands to the sequence 1 2 3.
The final expression executed by the shell after all expansions are applied is equivalent to:
let N=1 N=N*1 N=N*2 N=N*3 ... N=N*$1
factorial() ( IFS=\*; let N=$1-1 k="$*" && factorial "$N" "$k" || echo ${2-1} )