-3

I am writing a bash script and want to add some simple validation tests. The input should be either 1 or 2 and the script should ask for input again until the correct input is given.

I was thinking of doing this using an until loop but it didn't work. I tied until [ $group -eq 1 ] (where $group is the value given by the user) but obviously I also need a 2nd input. How can I do this correctly?

terdon
  • 242,166
  • 1
    Your question is quite unclear. Show your code – user1700494 Mar 03 '16 at 10:44
  • 1
    We can't help if you don't show i) the exact code you used, what you show is a syntax error and ii) the error message you received. Please [edit] and clarify. – terdon Mar 03 '16 at 11:03
  • @StéphaneChazelas I edited it to make it clearer. I was hoping the OP would do so instead. – terdon Mar 03 '16 at 12:24

4 Answers4

3
until
  printf 'Please enter 1 or 2: '
  IFS= read -r line || exit # exit on EOF
  [ "$line" = 1 ] || [ "$line" = 2 ]
do
  printf >&2 '"%s" is neither 1 nor 2, try again.\n' "$line"
done

With IFS= and -r, the input line is stored as-is in $line. You may want to omit the IFS= so that blanks (assuming you've not modified $IFS) are automatically stripped from the beginning or end of the input.

If the input has to be the 1 or 2 strings only, then you want to use =, not -eq.

If you want to allow other expressions of the 1 or 2 numbers, like 01, 1+1, 1.0, 100e-2, exp(0), RANDOM (sometimes), then you could use -eq, but note that not all shells accept all types of expressions above (ksh93 will accept them all, but bash would only accept things like 1 (leading and/or trailing blanks), or 0001 (leading zeros)), and that means you'll get error messages for inputs that don't form valid arithmetic expressions.

With shells that interpret arithmetic expressions, that's also dangerous as that can change variable values (like for an input like PATH=123) or even run arbitrary commands (like for inputs like a[0$(cmd>&2)]).

Depending on the shell, you could also get false positives on 18446744073709551617 or 4294967297 (or any other multiple of 232 or 264 + 1 or 2) as most shells use 64bit or 32bit integer numbers.

Whatever you do, do not use the -o and -a binary test/[ operators. Those should be banished as they make the parsing of the [ command potentially ambiguous and in practice unreliable (and are now marked obsolete in the POSIX spec).

For instance:

$ line='!' sh -c '[ "$line" = 1 -o "$line" = 2 ]'
sh: line 0: [: too many arguments

And remember to quote your variables ("$line", not $line which would undergo split+glob).

1

This should work, combine them with or (-o):

#init group variable
group=0
#read until value is either 1 or 2
until [ $group -eq 1 -o $group -eq 2 ]; 
    do 
    #your script...

    #read user input and put it in group
    read -p "Which group?" group 
done

You can also use || as or operator:

until [ $group -eq 1 ] || [ $group -eq 2 ]

Although in some cases, for example when you use the error code ($?) the first options is better, see this answer.

agold
  • 533
  • 5
  • 12
  • With the default value of IFS, that would accept inputs like 1 -o 1 or ! 0. I can't think of any reason why you would want to invoke the split+glob operator here. – Stéphane Chazelas Mar 03 '16 at 12:33
1
while IFS= read -r; do
    case "$REPLY" in
        1|2) break ;;
        *)   echo 'Error' >&2 ;;
    esac
done

This code snipped reads a value from standard input and then tests it against 1 and 2. If matching either string, the loop exits, otherwise a terse diagnostic message is produced and the loop continues.

Kusalananda
  • 333,661
-1

Just add the second condition to the expression using the or operator -o.

Murphy
  • 2,649
  • 2
    -o and -a [ binary operators should be avoided, they make the parsing of the [ command potentially ambiguous and in practice unreliable. Use [ "$i" = 1 ] || [ "$i" = 2 ] instead. – Stéphane Chazelas Mar 03 '16 at 10:47
  • @StéphaneChazelas Can you provide any sources for this claim? While your alternative seems to be valid, I consider it a solution to a problem most people don't have... – Murphy Mar 03 '16 at 10:50
  • 1
    See link in my answer. – Stéphane Chazelas Mar 03 '16 at 11:52
  • @Murphy: [ "!" = 1 -o 1 = 1 ] raise error in most shells except zsh. – cuonglm Mar 03 '16 at 12:24
  • @cuonglm I think that should go to Stéphane, shouldn't it? The OP was using the correct numerical operator, and I didn't advise against it. – Murphy Mar 03 '16 at 12:26
  • @BinaryZebra Well, it is an incomplete answer to an incomplete question, but as far as I can see it's technically correct and a solution to the problem. Does this justify deletion? – Murphy Mar 03 '16 at 12:29
  • The answer to my previous comment seems to be here: http://meta.stackexchange.com/questions/244987/recommend-deletion-needs-another-type-for-low-quality-posts – Murphy Mar 03 '16 at 12:39
  • @Murphy Technically, The correct description is to add the second test as this: [ "$group" = 1 ] || [ "$group" = 2 ] the -o or -a binary operators are Marked obsolete in the POSIX spec. But that is just secondary. The same way as I can make a comment with all this information, you could have given your point of view in a comment. The text of this answer is quite small (and, as you say, incomplete). –  Mar 03 '16 at 16:22
  • @cuonglm the correct syntax is: [ ! 0 = 1 -o 1 = 1 ] if you want to negate a test of 0 = 1 or [ 'x!' = 'x1' -o 1 = 1 ] if you want to use the ! as text and both work in most shells. –  Mar 03 '16 at 16:38
  • @BinaryZebra: Of course, the purpose of example to show how weird -o/-a can be. – cuonglm Mar 03 '16 at 16:41
  • @StéphaneChazelas Thank you very much for the update, I just added this to our knowledge base and will strive to apply it for new scripts. The Linux manpages aren't updated yet, I will send a notice to MTK/linux-man. – Murphy Mar 04 '16 at 10:27
  • @Murphy, that's not a Linux manpage as maintained by mtk, that man page is maintained within coreutils (as a short description derived from the help message of GNU test). The info page has the manual for GNU test, and it does say there to avoid -a and -o. In anycase, test/[ is built in all modern Bourne-like shells, so it's not GNU test you invoke when you call [ or test in a Bourne-like shell script. – Stéphane Chazelas Mar 04 '16 at 10:35
  • @StéphaneChazelas Well, can then be assumed that the bash builtins suffer from the same problem? However, the mail is already on the way, let's see what comes out of that. – Murphy Mar 04 '16 at 10:41
  • 1
    http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22909 – Murphy Mar 04 '16 at 18:37