242

My code:

    #!/bin/sh
    #filename:choose.sh
    read choose
    [ "$choose" == "y" -o "$choose" == "Y" ] && echo "Yes" && exit 0
    [ "$choose" == "n" -o "$choose" == "N" ] && echo "No"  && exit 0
    echo "Wrong Input" && exit 0

But when I execute

    sh ./choose.sh

terminal prompt me that

   [: 4: n: :Unexpected operator
   [: 5: n: :Unexpected operator

Is there any mistake in my bash script? Thanks!

6
  • When i executed the same code in Linux and in cygwin i was not getting any errors Commented Aug 5, 2010 at 1:11
  • 3
    Cygwin has most likely aliased sh to bash. Some distributions don't offer a true sh anymore. Although some will argue (and I tend to agree) that if you're writing a script to be portable, write it in sh instead of bash. Commented Aug 5, 2010 at 1:27
  • My issue was that I needed to source foobar.sh not ./foobar.sh Commented Aug 30, 2016 at 16:36
  • 5
    Two mistakes: 1. use "=" not "==" for /bin/sh 2. doesn't handle the empty string. Do ${choose}BLAH == yBLAH to fix that. So also this is technically not a duplicate question. Commented Sep 21, 2017 at 17:38
  • @personal_cloud, please don't recommend the ${choose}BLAH approach -- it's much better to just quote, with "$choose"; constant prefixes/suffixes haven't been needed since the 1970s (as long as features marked obsolescent in the current POSIX test standard, like -a or -o, are avoided). Commented Oct 31, 2019 at 16:04

7 Answers 7

406

There is no mistake in your bash script. But you are executing it with sh which has a less extensive syntax

So, you'll need run bash ./choose.sh instead, or convert the script to use POSIX compliant sh commands only, such as = between strings instead of ==.

Sign up to request clarification or add additional context in comments.

11 Comments

bash syntax is a superset of sh syntax - the /bin/sh executable on your system may provide only standard sh functionality, in which []-style tests are not included.
Yes. They are completely different shells. Although, bash was based on and is largely backwards-compatable with sh, and they might actually be the same program on your system, but will still behave differently depending on which name you use. You can have the script run with bash automatically by changing the first line to #!/bin/bash and making the file executable, and just running ./choose.sh.
This answer is partially wrong. The fully correct one is the now top-voted by Nietzche-jou. sh supports [. == works in Bash built-ins [[, test and [ while a single = is required by POSIX version of [ and test. (Bash manual says the same, BTW.) Requiring Bash because of this is needless harm to portability. Command name is [ or test, ] is just non-necessary, unused last parameter. Many shells implement these as built-ins, as Wikipedia says.
@Palec: while the answer is not as extensive as Nietzche-jou's answer, I do not see what would be wrong about it? I never mentioned anything about brackets :) +1 for your comment regardless!
@Wolph By writing partially wrong I meant two things. First, the problem is not in Bash vs sh syntax, both can call [ command correctly. It is in syntax of the [ command parameters, which is not sh’s business. Second, Bash is overkill for such a job, especially when a much simpler solution exists. This is not really wrong as it solves the problem too, but I think it is generally bad advice. This leads beginners to false conclusion that Bash solves their problems. It has many unportable extensions over POSIX-required features. I believe we should lead beginners to writing portable programs.
|
392

POSIX sh doesn't understand == for string equality, as that is a bash-ism. Use = instead.

The other people saying that brackets aren't supported by sh are wrong, btw.

5 Comments

Yes,I try to just replace the "==" for "=",the script can also be executive by "sh ./choose.sh".Both bash and sh support the brackets.
+1 This is a better answer than unnecessarily using bash, IMO.
In my specific case, My Teamcity agent is running sh by default, and I do not want to change that (it generates other issues). SH is required here, and I think that this is the correct answer for people that must use sh
+1 This is the right answer. Anyone looking to solve it for sh should just use single '='. Only reading the top voted reply by Wolph wasted my 3 hours :(
Still a very valuable tip. Lots of docker images have sh and no bash.
9

To execute it with Bash, use #!/bin/bash and chmod it to be executable, then use

./choose.sh

Comments

6

you can use case/esac instead of if/else

case "$choose" in
  [yY]) echo "Yes" && exit;;
  [nN]) echo "No" && exit;;
  * ) echo "wrong input" && exit;;
esac

Comments

5

you have to use bash instead or rewrite your script using standard sh

sh -c 'test "$choose" = "y" -o "$choose" = "Y"'

3 Comments

I think it is more convenient using "[ ]" instead of "test". It seemed that "bash ./choose.sh" can solve the problem.
@kit either way, sh is more little portable
@kit.yang How are brackets more convenient? The historical confusion caused by people failing to realize that [ is a synonym for test and the continuing errors made through omitted whitespace around the brackets hardly compensate for the single character saved. ("if [ $x = 5 ]" vs "if test $x = 5"; 13 chars vs 14).
5

In fact the "[" square opening bracket is just an internal shell alias for the test command.

So you can say:

test -f "/bin/bash" && echo "This system has a bash shell"

or

[ -f "/bin/bash" ] && echo "This system has a bash shell"

... they are equivalent in either sh or bash. Note the requirement to have a closing "]" bracket on the "[" command but other than that "[" is the same as "test". "man test" is a good thing to read.

3 Comments

man test is the manpage of /bin/test not for the built-in shell function
ls $(which [) gives /usr/bin/[
didn't work for me.
-6

Do not use any reserved keyword as the start of any variable name: eg HOSTNAME will fail as HOST {TYPE|NAME} are reserved

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.