I have been trying to learn loops, and I have the following:
Guessing_Game() {
echo "Guessing Game!"
set loopSwitch = 0
until [[ $loopSwitch == 1 ]];
echo $loopSwitch
do
read -p "Guess a number between 1 and 10: " userGuess
if [[ $userGuess == 6 ]];
then
echo "Well done! You win."
else
echo "Incorrect guess."
fi
read -p "Would you like to play again? (y/n)" playAgain
if [[ $playAgain == "n" ]];
then
set loopSwitch = 1
fi
done
}
From what I have read, as the loopSwitch variable was set outside of the subshell, it can only change the value within that subshell?
How can I go about setting the loopSwitch variable so that I can exit the loop?
I have tried echoing out the variable $loopSwitch through several portions of the code - just after the entry into the until loop, inside the last if statement - and nothing is output, so I'm thinking it just doesn't exist within the until loop?
For the
set loopSwitch = 1
portion, I've tried:
set loopSwitch = 1
set $loopSwitch = 1
loopSwitch = 1
$loopSwitch = 1
Any help would be appreciated, whether that be with the code or constructs as a whole.
As others have mentioned, there is no subshell in your code. I think you probably saw code like
num=27; seq 3 | while IFS= read -r line; do num="$line"; echo "inside: $num"; done; echo "outside: $num"
which would output 1, 2, 3, 27 and misunderstood why that outputs 27 instead of 3 at the end. It's not because loops run in a subshell, but because the commands on both sides of a pipe (|) run in a subshell. That's why you'd use command substitution (<(command)
) to write
num=27; while IFS= read -r line; do num="$line"; echo "inside: $num"; done < <(seq 3); echo "outside: $num"
which would output 1, 2, 3, 3 instead. See mywiki.wooledge.org/BashFAQ/024.
Regarding the code in your question, FWIW I'd write it as:
$ cat tst.sh
#!/usr/bin/env bash
Guessing_Game() {
local keepPlaying theNumber userGuess
echo 'Guessing Game!'
theNumber=$(shuf -n 1 -i 1-10)
until [[ "$keepPlaying" =~ [nN] ]]; do
echo "$keepPlaying"
IFS= read -r -p 'Guess a number between 1 and 10: ' userGuess
if (( userGuess == theNumber )); then
echo "Well done! You win."
else
echo "Incorrect guess."
fi
IFS= read -r -p 'Would you like to play again? ([y]/n)' keepPlaying
done
}
Guessing_Game
The changes I made were:
bash
in the callers PATH
.((...))
for numeric comparisons.IFS=
and -r
on the read
s as you always should unless you have a specific need to remove either of them, see why-is-using-a-shell-loop-to-process-text-considered-bad-practice.loopSwitch
as it meant almost exactly the same thing as playAgain
and then renamed playAgain
to keepPlaying
so it made slightly more sense for the first loop iteration too.6
. If you don't have shuf
that can do this job just google "shell random number between 1 and 10" or similar.keepPlaying
case-independent.set
s as they're unnecessary and I don't know why anyone would use that.