4


I am a bit struggling with bash programming, because I don't seem to understand the syntax rules. For example:

read confirm
if [ "$confirm" == "yes" ]; then
    echo "Thank you for saying yes"
else
    echo "Why did you say no?"
fi

In this code, you can use many forms to do the same thing:

"$confirm" == "yes"
$confirm == "yes"
"$confirm" == yes
$confirm == yes

So what is the rule? Besides that, it is very strict, so if you write the above if statement without the space between '[' and '"', you would get an error. So my questions:

  1. Can anybody give me an idea about the 'basic' rules of syntax in shell scripting? You can call it grammar if you want.
  2. There are three different shell programming scripts as far as I know. Which one of them is the easiest to learn for programmers of languages like C++, C#, and Java?

Regards,
Rafid

Rafid
  • 18,991
  • 23
  • 72
  • 108
  • 4
    All the shell languages are horrible, though some are more horrible than others, and all are better than Windows's cmd.exe. My advice is to stick with bash, which is the most popular. `man bash` should give you the (enormous, convoluted) syntax rules. – j_random_hacker Dec 09 '10 at 09:36
  • @j_random_hacker: Thank you very much for making me more confident :-) Could you please post this comment as an answer? This way I can 'accept' your answer if there are no better answers. – Rafid Dec 09 '10 at 09:40
  • @Greg: Same comment for you, why don't you post the comment as an answer? – Rafid Dec 09 '10 at 09:41

8 Answers8

12

The rules are simple but subtle. The examples you gave are not all equivalent, they have subtly different meanings. For a fairly good reference you can read Shell Command Language, which covers POSIX shells. Most shells, certainly including bash, zsh and ksh, are POSIX shells and will implement at least what is listed there. Some shells may conform to earlier versions of the specification or be similar but not conformant.

The primary rule that you will need to remember if you are learning Unix shell scripting is this: Expressions are separated by spaces. Technically they are separated by whatever characters are listed in the variable $IFS, but this amounts to whitespace under normal circumstances.

If you say ["$a"="$b"] in bash the shell tries to read the entire string as a command, evaluating $a and $b in place. Supposing the value of $a was a literal a and the value of $b was a literal b, the shell would attempt to execute a command called [a=b], which is a legal file name. The quotation marks were interpreted by the shell as special but the [ was not, because it is only special if written as a separate token. It was not separated by spaces.

Almost everything you see and do in a shell is a command. The character [ isn't syntax, it's a command. Commands take arguments, separated by spaces. What those arguments mean is up to the command, not the shell. In C if ( a == b ) is handled all by the parser, except for the values of a and b. In bash if [ "$a" == "$b" ] is first parsed by the shell, which evaluates the variables $a and $b, and then the command [ is executed. Sometimes this is a shell builtin command, sometimes it is literally a separate executable (look for /bin/[ in your system). This means that a == b ] is not interpreted by bash at all but instead is a kind of domain-specific language that is interpreted by [, which is also known as test. In fact you can write if test "$a" == "$b" instead. In this form test does not require the closing ], but everything else is the same. To see what test will do with these arguments read help test or man test.

The other rule to remember when learning Unix shell scripting is this: Variables are expanded first, commands are evaluated second. This means that if you have a space in a variable, such as foo="a b" then the shell will see the space after the variable is expanded: ls $foo by itself will complain that it cannot find the file a and it cannot find the file b. To get the behavior you probably expect from other languages you almost always will want to quote your variables: ls "$foo", which instructs the shell that the expanded variable is to be treated as a single string and not re-tokenized.

Shell scripting is filled with oddities but it is not irrational (at least not most of the time). Some historical warts do exist but there are really not very many rules to remember once you get the hand of the basics. Just do not expect it to operate like a conventional C-like language and you won't be too surprised.

sorpigal
  • 25,504
  • 8
  • 57
  • 75
  • An answer can't be better than this! Thank you very much, I feel I understand what my problem "was" :-) – Rafid Dec 11 '10 at 07:04
2

One problem is that if you do:

if [ $foo == "bar" ] ...

and then $foo is empty, you would get a syntax error. That could be solved by e.g.

# prepend both with an 'x' (or any other char)
if [ x$foo == "xbar" ] ..
# or enclosing in quotes (not sure this works on all shells)
if [ "$foo" == "bar" ] ...

Putting stuff inside quotes also makes sure that whitespaces are preserved for the comparison.

Today, there are other more advanced ways to use expressions inside if-statements, for example the double brackets

if [[ $foo == bar ]]

see this SO question for more details about that.

As for choosing which script dialect to learn, I'd suggest learning bash as that is by far the most common one. If you want to write portable scripts, then limiting yourself to the old 'sh' dialect which isn't as advanced, but should be supported by almost all unix shells.

The C-shell might be syntax wise more easy for C-style programmers to learn (since the syntax matches C more closely), but it is less common in the wild

Community
  • 1
  • 1
Isak Savo
  • 34,957
  • 11
  • 60
  • 92
  • See [Greg's comment](http://stackoverflow.com/questions/4396659/easiest-shell-for-c-c-java-programmers/4396784#4396784) regarding the C-shell. – Dennis Williamson Dec 09 '10 at 15:41
2

The most basic grammar rule in bash is:

<command> <space>+ <arguments>

That is, the command and arguments must be separated by one or more spaces. [ is a command, so omitting the space after it is an error.

As for which is "better", I echo j_random_hacker's comment:

All the shell languages are horrible, though some are more horrible than others, and all are better than Windows's cmd.exe. My advice is to stick with bash, which is the most popular.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • But how does grammar rule applies to variable assignment? VARIABLE = "SOME TEXT" would be an error because of the spaces around the '=' sign. So what is the rule in this case? – Rafid Dec 09 '10 at 09:44
  • 2
    Variable assignment is not a command, so it doesn't fall under the grammar rule given. The rule for just assignment is ` <=> ` – Ignacio Vazquez-Abrams Dec 09 '10 at 09:56
2

Here's some useful links for bash tips:

Community
  • 1
  • 1
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
2

To be really safe you schould use:

"$confirm" == "yes"

as this makes sure that bash will consider both values to be just strings. Otherwise, they are subject to expansion/substitution which may give unexpected results or/and syntax errors.

As for the syntax error when you ommit the space between opening brace and quote -- opening brace "[" is just an alias for the "test" shell builtin. So your condition can be also written as:

read confirm
if test "$confirm" == "yes"; then
    echo "Thank you for saying yes"
else
    echo "Why did you say no?"
fi

In fact, on some systems there is a file in /usr/bin with the name of [, that is linked to test command (in case if some shell doesn't have "[" as a shell builtin command).

Jacek Prucia
  • 1,026
  • 2
  • 12
  • 22
2

All the shell languages are horrible, though some are more horrible than others, and all are better than Windows's cmd.exe. My advice is to stick with bash, which is the most popular. man bash should give you the (enormous, convoluted) syntax rules.

j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
1

I suggest you check out tcsh. It's syntax is more similar to C.

Johan Kotlinski
  • 25,185
  • 9
  • 78
  • 101
  • 3
    The C shell is not really suitable for scripting: [Top 10 reasons not to use the C shell](http://www.grymoire.com/Unix/CshTop10.txt) – Greg Hewgill Dec 09 '10 at 09:48
1

For more regarding [[, test and [ see these answers:

Community
  • 1
  • 1
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439