0

I created a function that asks a user to guess how many files are in the directory, and I am trying to check whether the input is valid. For line 18, I am trying to check whether the input contains words and if so inform the user that it is not a valid input. However, I receive the following error:

guessinggame.sh: line 18: conditional binary operator expected
guessinggame.sh: line 18: syntax error near `$response'
guessinggame.sh: line 18: `    elif [[ echo $response | egrep "\w" response.txt ]'

Here is my code:

function guessinggame {
num_input=true
while $num_input
do
  echo 'Guess how many files are in the current directory. Type in a number and 
        then press Enter:'
  read response
  echo $response > response.txt
  if [[ $response -eq 3 ]]
  then
    echo 'Congratulations! You guessed correctly!'
    num_input=false
  elif [[ $response -gt 3 ]]
  then
    echo '$response is too high! Guess again.'
  elif [[ $response -lt 3 ]]
  then
    echo '$response is too low! Guess again.'
  elif [[ echo $response | egrep "\w" response.txt ]]
  then
    echo '$response is not a number! Please enter a valid input.'
  else
    echo '$response is not a number! Please enter a valid input.'
  fi
num_input=$num_input
done
}
guessinggame

How do I resolve this error? What am I doing wrong?

  • 2
    Paste this into https://www.shellcheck.net/ and fix everything it tells you. You have missing closing quotes, a missing closing `]` in `[[ ... ]]`, single quoted strings containing variables... – Benjamin W. Sep 11 '18 at 20:22
  • 1
    Also, `num_input=$num_input` doesn't do anything. – Benjamin W. Sep 11 '18 at 20:24
  • Either use `echo text | grep ...` or `grep ... file`, but not `echo text | grep ... file`. Remove the `[[ ]]` braces and add `-q`: `elif ... grep -Eq ...`. – Socowi Sep 11 '18 at 20:30
  • Okay, I fixed the single quote issue and added a bracket to line 18, but I still get an error for line 18. – Infinite Learning Loop Sep 11 '18 at 20:32
  • I also tried both `echo text | egrep ...` and `egrep ... file`. Both gave me the same error above. – Infinite Learning Loop Sep 11 '18 at 20:42
  • 2
    Are you still trying to put those inside `[[ ]]`? `[[` is the extended `test` command. Neither `echo` nor `grep` is an argument to `test`, either extended or otherwise -- so you can run `if echo foo | grep`, but *cannot* write `if [[ echo foo | grep ]]`. – Charles Duffy Sep 11 '18 at 21:41
  • 1
    ...which is to say, `[[` is a **command**, it's not part of the syntax of `if`. – Charles Duffy Sep 11 '18 at 21:44

1 Answers1

4

Here you go, the regex is working for me:

#!/bin/bash
guessinggame() {
  local num_input response
  num_input=1
  while (( num_input )); do 
    echo 'Guess how many files are in the current directory. Type in a number and 
          then press Enter:'
    read -r response
    echo "$response" > response.txt

    if ! [[ "$response" =~ ^[0-9]+$ ]]; then
      echo "$response is not a number! Please enter a valid input."
    elif (( response == 3 )); then
      echo 'Congratulations! You guessed correctly!'
      num_input=0
    elif (( response > 3 )); then
      echo "$response is too high! Guess again."
    elif (( response < 3 )); then
      echo "$response is too low! Guess again."
    else
      echo "$response is not a number! Please enter a valid input."
    fi
    num_input=$num_input
  done
}

guessinggame
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Ashutosh
  • 518
  • 7
  • 20
  • 3
    The regex may work, but there a lot of bad practices in this code. Since SO answers are a teaching resource, would you consider doing a more complete cleanup? (See everything http://shellcheck.net/ identifies, plus the notes on function declaration syntax at http://wiki.bash-hackers.org/scripting/obsolete; also, using `true` and `false` as booleans is a dangerous practice, insofar as it's easy for uninitialized variables to lead to arbitrary command execution). – Charles Duffy Sep 11 '18 at 21:49
  • Let me update my answer according to best practices. – Ashutosh Sep 11 '18 at 21:50
  • @CharlesDuffy I'm not getting your last point about `uninitialized variables to lead to arbitrary command execution`. Can you explain more about it? – Ashutosh Sep 11 '18 at 21:57
  • 3
    If this code were structured differently, such that `num_input` weren't always initialized to `true`, then if the prior value of that variable contained a command other than `true` or `false`, then that command (whatever it was) would be run by the `while $num_input` command. It's safer to run `while [[ $num_input = true ]]`, or to store booleans as numbers (`num_input=1`) and use `while (( num_input )); do`. – Charles Duffy Sep 11 '18 at 21:59
  • 3
    (similarly, the `while $num_input` pattern means that any point you're relying on another function, a `read` command, etc. to populate a variable with `true`/`false`, you need to worry about whether that function, content that `read` is consuming, etc. crosses a trust boundary). – Charles Duffy Sep 11 '18 at 22:00
  • 2
    ...btw, I'd consider `(( response == 3 ))`, `(( response > 3 ))` and `(( response < 3 ))` rather than `[[ $response ... ]]` and needing `-eq`/`-gt`/`-lt`; if you're going to use bashisms, might as well choose ones that help readability as much as possible. :) – Charles Duffy Sep 11 '18 at 22:01
  • 2
    I'd also consider declaring your variables: `local num_input response` at the top of the function will stop it from changing global variables even after it leaves scope. – Charles Duffy Sep 11 '18 at 22:02
  • Wow that was a great information for me. I have improved my answer as per your suggestions. Let me know what you think @CharlesDuffy? – Ashutosh Sep 11 '18 at 22:08
  • Made a few more little tweaks, feel free to roll them back if you disagree. Overall, a big improvement! – Charles Duffy Sep 11 '18 at 22:16
  • @CharlesDuffy I totally agree with you! Keep sharing the great knowledge you have. :) – Ashutosh Sep 11 '18 at 22:18
  • Wow, I'm new to bash programming so this helps a lot! – Infinite Learning Loop Sep 11 '18 at 22:24
  • @CharlesDuffy what is the difference between double parentheses `((` and double brackets `[[` in bash? – Infinite Learning Loop Sep 11 '18 at 22:29
  • 3
    The double parenthesis enter a C-style arithmetic context, whereas the double brackets enter a shell syntax extension inspired by the `test` command (aka `[`). [BashFAQ #31](http://mywiki.wooledge.org/BashFAQ/031) covers `[` and `[[` pretty well, whereas http://wiki.bash-hackers.org/syntax/arith_expr covers the POSIX-standardized `$(( ))` and its bash-extension `(( ))` cousin. – Charles Duffy Sep 11 '18 at 22:34