#@@ luhn - check a number for validity using the Luhn formula
#@ USAGE: luhn [-n|-v] NUMBER
#@ NOTE: Non-digits are allowed in NUMBER and will be skipped over
#@ OUTPUT: none
#@ EXIT_CODE: 0 if NUMBER is valid, otherwise 1
#@ OPTIONS: -n Generate checksum digit for number supplied and print
#@ -v Print OK or Not valid; with -n, -v has no effect
case $1 in
--help) printf "%sn" 
"luhn - check a number for validity using the Luhn formula
USAGE: luhn [-n|-v] NUMBER
NOTE: Non-digits are allowed in NUMBER and will be skipped over
OUTPUT: none unless -v is used
EXIT_CODE: 0 if NUMBER is valid, otherwise 1
OPTIONS: -n Generate checksum digit for number supplied and print
-v Print OK or Not valid; with -n, -v has no effect
"
exit
esac
_ld() #@@ Double a [single-digit] number and, if >10, add both digits
{ #@ USAGE: _ld N
#@ RESULT: stored in $_LD
#@ OUTPUT: none
#@ RETURN: 0 if $1 is a single digit, otherwise 5
case $1 in
0) _LD=0 ;;
1) _LD=2 ;;
2) _LD=4 ;;
3) _LD=6 ;;
4) _LD=8 ;;
5) _LD=1 ;;
6) _LD=3 ;;
7) _LD=5 ;;
8) _LD=7 ;;
9) _LD=9 ;;
*) _LD=; return 5 ;;
esac
}
n=1
gen=
verbose=0
while getopts vn opt
do
case $opt in
n) gen=0 ;;
v) verbose=$(( verbose + 1 )) ;;
esac
done
shift $(( $OPTIND - 1 ))
sum=0
#: If check digit generation is requested, tack on dummy digit, 0
number=$1$gen
while [ -n "$number" ]
do
#: Split $number into last digit and everything else
left=${number%?} #~ Everything but the last character
digit=${number#"$left"} #~ The last character
number=$left #~ Discard last character
#: Skip non-digits
case $digit in
[0-9]) ;;
*) continue ;;
esac
#: Calculate checksum
case $n in
*[24680]) _ld "${digit:-0}" || exit
sum=$(( $sum + $_LD ))
;;
*) sum=$(( $sum + ${digit:-0} )) ;;
esac
n=$(( $n + 1 ))
done
if [ -z "$gen" ]
then
case $sum in
*0) [ "$verbose" -gt 0 ] && echo OK ; true ;;
*) [ "$verbose" -gt 0 ] && echo Not valid ; false;;
esac
else
printf "%sn" $1$(( 10 - ( $sum % 10 ) ))
fi

Luhn sh

  • 1.
    #@@ luhn -check a number for validity using the Luhn formula #@ USAGE: luhn [-n|-v] NUMBER #@ NOTE: Non-digits are allowed in NUMBER and will be skipped over #@ OUTPUT: none #@ EXIT_CODE: 0 if NUMBER is valid, otherwise 1 #@ OPTIONS: -n Generate checksum digit for number supplied and print #@ -v Print OK or Not valid; with -n, -v has no effect case $1 in --help) printf "%sn" "luhn - check a number for validity using the Luhn formula USAGE: luhn [-n|-v] NUMBER NOTE: Non-digits are allowed in NUMBER and will be skipped over OUTPUT: none unless -v is used EXIT_CODE: 0 if NUMBER is valid, otherwise 1 OPTIONS: -n Generate checksum digit for number supplied and print -v Print OK or Not valid; with -n, -v has no effect " exit esac _ld() #@@ Double a [single-digit] number and, if >10, add both digits { #@ USAGE: _ld N #@ RESULT: stored in $_LD #@ OUTPUT: none #@ RETURN: 0 if $1 is a single digit, otherwise 5 case $1 in 0) _LD=0 ;; 1) _LD=2 ;; 2) _LD=4 ;; 3) _LD=6 ;; 4) _LD=8 ;; 5) _LD=1 ;; 6) _LD=3 ;; 7) _LD=5 ;; 8) _LD=7 ;; 9) _LD=9 ;; *) _LD=; return 5 ;; esac } n=1 gen= verbose=0 while getopts vn opt do case $opt in n) gen=0 ;; v) verbose=$(( verbose + 1 )) ;; esac done shift $(( $OPTIND - 1 )) sum=0 #: If check digit generation is requested, tack on dummy digit, 0 number=$1$gen while [ -n "$number" ] do #: Split $number into last digit and everything else left=${number%?} #~ Everything but the last character
  • 2.
    digit=${number#"$left"} #~ Thelast character number=$left #~ Discard last character #: Skip non-digits case $digit in [0-9]) ;; *) continue ;; esac #: Calculate checksum case $n in *[24680]) _ld "${digit:-0}" || exit sum=$(( $sum + $_LD )) ;; *) sum=$(( $sum + ${digit:-0} )) ;; esac n=$(( $n + 1 )) done if [ -z "$gen" ] then case $sum in *0) [ "$verbose" -gt 0 ] && echo OK ; true ;; *) [ "$verbose" -gt 0 ] && echo Not valid ; false;; esac else printf "%sn" $1$(( 10 - ( $sum % 10 ) )) fi