Recursively compute factorial of positive integer using only built-ins

factorial() ( IFS=\*; let N=$1-1 k="$*" && factorial "$N" "$k" || echo ${2-1} )

November 25, 2019CK

Explanation

A recursive function that leverages the arithmetic expansions evaluated by the let command, and the significance of the field separator when arguments are expanded using "$*".

  • IFS=\* concatenates the arguments "$*" using a * symbol, which let interprets as a multiplication operator

  • let N=$1-1 k="$*" assigns arithmetic values to variables N and k. N will have a value one less than the first argument; k will be the product of all the arguments

  • && performs the command immediately to its right if and only if the expression immediately to its left is successful (has exit code 0)

  • factorial "$N" "$k" calls itself with the first argument being one less than it was, and the second argument being the cumulative product of the arguments thus far across all iterations

  • || performs the command immediately to its right if the previous command failed (has exit code non-zero)

  • echo ${2-1} prints the second argument, if there is one (the factorial), or else 1

Finally, notice that we defined the function using the syntax name() (...) instead of the more conventional name() { ...; }. When using the format with (...), the function body is executed in a sub-shell. This is important to make it safe to overwrite the value of the IFS variable.

Limitations

If a positive integer is not the one and only argument passed to it when invoked by the user, the result will be nonsense or an error will be thrown.

Related one-liners

Compute factorial of positive integer

fac() { { echo 1; seq $1; } | paste -s -d\* | bc; }

May 21, 2014jeroenjanssens

Alternative one-liners

Compute factorial of positive integer using only built-ins

factorial() { local N; eval let N=1 N*={1..$1}; echo "$N"; }

November 29, 2019CK