There is no correct answer to your question!
Personally, I'd find out if Bash provides enough functionality. I'd prefer an interpreted "script" language over a compiled one, since these kinds of programs tend to evolve over time, and having it be trivial to fix issues or add new features is extremely useful. I'd start with Bash, simply because I've done a lot of similar stuff with Bash, and it seems to fit.
To show you how simple similar stuff is in Bash, here is a commented version of guess-the-number game:
Code:
#!/bin/bash
# Range of random values allowed (integers only)
MIN_VALUE=1
MAX_VALUE=1000
# Generate a random value using the RANDOM special variable.
VALUE=$(( MIN_VALUE + ( RANDOM % (MAX_VALUE - MIN_VALUE + 1 ) ) ))
# Output the premise.
printf 'I\047m thinking of a number between %d and %d, inclusive.\n' $MIN_VALUE $MAX_VALUE
# No tries yet. Loop.
TRIES=0
while read -p 'Your guess: ' GUESS ; do
# Handle special values of guess:
case "$GUESS" in
[A-Za-z]*) # Anything beginning with a letter?
printf 'You give up? I was thinking of %d.\n' $VALUE
exit 1
;;
*) # Everything else.
# Is GUESS not valid arithmetic expression?
if ! ( exec &>/dev/null ; GUESS=$(( $GUESS )) ); then
printf 'I don\047t understand what you mean by "%s". Try again.\n' "$GUESS"
continue
fi
GUESS=$(( $GUESS ))
;;
esac
# Make sure GUESS is an integer.
GUESS=$(( GUESS )) || exit $?
# If GUESS is outside the limits, complain.
if [ $GUESS -lt $MIN_VALUE ]; then
printf 'Your guess %d is under the minimum, %d. Try again!\n' $GUESS $MIN_VALUE
continue
fi
if [ $GUESS -gt $MAX_VALUE ]; then
printf 'Your guess %d is over the maximum, %d. Try again!\n' $GUESS $MAX_VALUE
continue
fi
# This is a new try.
TRIES=$(( TRIES + 1 ))
if [ $GUESS -gt $VALUE ]; then
printf '%d is too high.\n' $GUESS
elif [ $GUESS -lt $VALUE ]; then
printf '%d is too low.\n' $GUESS
else
printf '%d is right! You only used %d tries, too!\n' $VALUE $TRIES
exit 0
fi
done
Note that I am using the POSIX-compatible test operator
[ rather than the compound command
[[ most here will recommend you to use instead. That is because I want to keep my Bash scripts POSIX compatible; I sometimes need to run them using e.g.
dash instead. In fact, if you modify the line containing RANDOM to
Code:
VALUE=$( awk -v min=$MIN_VALUE -v max=$MAX_VALUE 'BEGIN { srand(); printf("%d\n", min+int(rand()*(max-min+1))) }' )
which uses
awk to generate the random value since POSIX shells do not provide
$RANDOM, the script also works if you run it using
dash (
#!/bin/dash).
Other details that come very handy with command-line scripts are
ANSI escape sequences. For example, I like to output important error messages in red:
Code:
message="Some error message"
errorcode=1
printf '\033[0;31mError %d: \033[1;31m%s\033[0;31m.\033[0m\n' $errorcode "$message" >&2
Note that if the script is not always interactive, it would be best to use ANSI escape sequences only if run interactively, with the output going to a terminal. To test if standard input, output, or error (
>&2) are terminals, you can use
Code:
if ( stty &>/dev/null ); then
echo "Standard input is a terminal"
fi
if ( stty &>/dev/null ) <&1 ; then
echo "Standard output is a terminal"
fi
if ( stty &>/dev/null ) <&2 ; then
echo "Standard error is a terminal"
fi
Something like this is very useful:
Code:
if ( stty &>/dev/null ) <&1 ; then
ANSI_RED="$(printf '\033[0;31m')"
ANSI_NORMAL="$(printf '\033[0m')"
else
ANSI_RED=""
ANSI_NORMAL=""
fi
printf "${ANSI_RED}"'No! Bad dog!'"${ANSI_NORMAL}"'\n̈́'
Note that I switch between double quotes and single quotes, because I don't want the shell to interpret
! or
\n.