2

I have a problem for which I need to write a program in shell script so I opened a book on linux that has a chapter on bash scripts. It seemed like a good idea to write a testscript to test the commands as I encountered them but the first script does not work and altering it in other obvious ways does not fix the problem.

The script as shown in the example is:-

#!/bin/bash
count=10
nextcount=$count + 1
echo $count
echo $nextcount

What the result of running this script should be

[Carl@localhost bin]$ testscript
10
11

However what actually results is

[Carl@localhost bin]$ testscript
/home/Carl/bin/testscript: line 3: +: command not found
10

with the error message indicating that the "+" sign is interpreted as a command not an addition operator.

If I remove the spaces surrounding the "+" sign so that the script becomes

#!/bin/bash
count=10
nextcount=$count+1
echo $count
echo $nextcount

[Carl@localhost bin]$ testscript
10
10+1

The line 3 statement instead of adding 1 to 10 to get 11 concatenates "10" "+" & "1"

Altering line3 to read nextcount=$count +1 or nextcount=$count+ 1 does not work either.

Finding insoluble problems with the first example in a text book on scripting should not happen. Am I going crazy?

4
  • 3
    Dump the book, you need (( ... )) to do arithmetics in bash. – nohillside Apr 6 '18 at 12:51
  • 1
    What book is it? – ilkkachu Apr 6 '18 at 13:17
  • @ilkkachu. The book is "Linux System Administration Black Book" by Dee-Ann LeBlanc published by Coriolis ISBN 1-57610-419-2 publication date unknown. Until this problem arose I had found that even 16 years old books on Linux are of use as much of the basics do not change and one can use the web when more up to date information is required. – Carlyle Moulton Apr 6 '18 at 20:33
  • If you're happy with one or several of the answers, upvote them. If one is solving your issue, accepting it would be the best way of saying "Thank You!" Accepting an answer also indicates to future readers that the answer actually solved the problem. – Kusalananda Apr 7 '18 at 6:19
6

As always, an assignment in the shell does not accept spaces (see: Spaces in variable assignments in shell scripts): something like var=foo bar runs the command bar with var set to foo. Or in your case, the command is +, which is just fine, since + has no special meaning to the shell (not in this context anyway). Also, var=1+1 takes the right hand side as the string 1+1, since the plus is just a regular character. If it had a special meaning (like ;, or (), you'd need to quote it.

The standard way to do arithmetic in the shell is the $(( ... )) expansion, so to add to a number, and assign it to a variable, use:

anothervar=$((var + 1))

If you're using Bash/ksh/zsh and just want to loop a constant number of iterations, you can use:

for (( i = 0; i < 10 ; i++)); do something ; done

( for i in {1..10} would also work, but in Bash, variable expansions don't work inside the brace expansion.)

2
  • @Kusalananda. Thankyou. I tried "nextcount=$((count + 1))" and it works. – Carlyle Moulton Apr 7 '18 at 3:28
  • @CarlyleMoulton That answer was written by ilkkachu, not me. If this solves your issue, please consider accepting the answer. – Kusalananda Apr 7 '18 at 6:20
1

Use the arithmetic expression syntax to do maths:

count=10
(( nextcount = count + 1 ))
0
0

It's possible to do something that looks similar to what you have shown, by using declare -i:

declare -i nextcount
nextcount=$count+1

That declares the variable nextcount with the integer attribute, which causes arithmetic evaluation to be performed on it automatically whenever it is assigned. (Run help declare in bash or look here for details.) This is not a standard POSIX shell feature, but bash supports it.

The assignment does not need to immediately follow the declare command. If it does, you may prefer to do it in the declare command, like this:

declare -i nextcount=$count+1

Any arithmetic expression with integers and arithmetic operators is supported. If the operators risk being interpreted specially by the shell in another way, you can quote the expression to prevent that. Remember, you're assigning text to the variable; arithmetic evaluation is performed on this text. For another example, after this command $x will expand to 13:

declare -i x='2 * 7 - 1'

Even if you removed the spaces, you would want that quoted because * would otherwise cause it to be interpreted as a glob, triggering filename expansion. Note that you must still not have spaces around =.

You might not usually do it this way, though. Often it is easier, more elegant, and more readable to use arithmetic expansion (with $) or arithmetic evaluation (without $) instead, as the other answers suggest. I present the method shown here not to encourage you to prefer it, but instead mainly because it is the closest thing to what your book showed that actually performs shell arithmetic.

Arithmetic expressions--by which I mean expressions that are evaluated using shell arithmetic because they are inside $(( )) or (( ))--permit you to use = with spaces around it. The = in the command ((count = 10)) does not work the same, syntactically, as the = in the command count=10.


If x has the integer attribute (declare -i x), you can even write things like this to assign a value to multiple variables, though I would suggest against it on the grounds that it is confusing:

x=y=z=10

If you're wondering what that does, here's a hint--this does the same thing:

x='y = z = 10'

That assigns the string y = z = 10 (or, in the first example, y=z=10) to x. It is important that at least x have the integer attribute. Assuming it does, that text is evaluated as an arithmetic expression. The subexpression z = 10 assigns 10 to z, but that subexpression also has a value, 10, which is assigned to y. That full expression, which is an assignment to y, also has a value, still 10.

Note that the first = is doing normal shell variable assignment, while the others are the arithmetic assignment operator. This is not special to the second form (the one that, by being quoted, is able to contain spaces). In x=y=z=10, too, the first = means something different from the other two =es, though you happen to be using them to achieve the same goal. This is potentially confusing. I recommend against writing stuff like that, except perhaps interactively for purposes of experimentation. You can write this command instead:

((x = y = z = 10))

That's straightforward arithmetic evaluation. All three = signs are the arithmetic assignment operator. It's still fine if you have declared some or all of the variables with the integer attribute--which I often advocate--but you do not need to have done so.


In a sort of similar vein, bash has a += operator that normally appends text:

$ x=foo
$ x+=bar
$ echo "$x"
foobar

(The leading $ characters on some lines are my prompt. I include them here to distinguish the input I am giving bash from the output it produces.)

But the attributes of the assigned-to variable affect what operation += performs. += is commonly used to extend indexed arrays:

$ a=(foo bar baz)
$ a+=(quux)
$ echo "${a[@]}"
foo bar baz quux

When a variable with the integer attribute is assigned to with +=, in-place addition is performed:

$ declare -i y=7
$ y+=2
$ echo "$y"
9

But bash also has += as an arithmetic operator, which I suggest using instead in most cases. That is, if y holds the value 2, you can write this instead to increase the value of y by 2:

((y += 2))

It also has the other traditional compound assignment operators (the ones that are present in the C language). For example, suppose I want to decrease the value of y by 3. This doesn't work:

$ y-=3
y-=3: command not found

But this works:

$ ((y -= 3))
$ echo "$y"
6

Or I could have just done this, which both changes y and prints the new value:

$ echo "$((y -= 3))"
6
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.