Rafid
Rafid

Reputation: 20229

Easiest Shell for C++/C#/Java Programmers


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

Upvotes: 4

Views: 959

Answers (8)

sorpigal
sorpigal

Reputation: 26096

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.

Upvotes: 12

j_random_hacker
j_random_hacker

Reputation: 51246

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.

Upvotes: 2

Jacek Prucia
Jacek Prucia

Reputation: 1076

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).

Upvotes: 2

Johan Kotlinski
Johan Kotlinski

Reputation: 25759

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

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 799150

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.

Upvotes: 2

Isak Savo
Isak Savo

Reputation: 35914

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

Upvotes: 2

Related Questions