I'm having trouble performing arithmetic expressions in UNIX - bash

I have the following script:
#!/bin/sh
r=3
r=$((r+5))
echo r
However, I get this error:
Syntax error at line 3: $ unexpected.
I don't understand what I'm doing wrong. I'm following this online guide to the letter http://www.unixtutorial.org/2008/06/arithmetic-operations-in-unix-scripts/

This sounds fine if you're using bash, but $((r+5)) might not be supported if you're using another shell. What does /bin/sh point to? Have you considered replacing it with /bin/bash if it's available?

The shebang line is your problem. bash is not sh. Change it to #!/bin/bash and it will work. You'll also want echo $r instead of echo r.

It works for me (printing 8), if you change echo r to echo $r. What version of sh do you have installed? What unix distribution?

You might want to try the following:
#!/bin/sh
r=3
r=$((r + 5))
echo $r

For doing maths (including decimals/floats), you can use awkor bc/dc.
awk -vr="$r" 'BEGIN{r=r+5;print r}'
or
echo "$r+5" | bc

Related

bash not recognizing new lines in multiline variable assignment [duplicate]

In Bash (or other shells) how can I print an environment variable which has a multi-line value?
text='line1
line2'
I know a simple usual echo $text won't work out of the box.
Would some $IFS tweak help?
My current workaround is something like ruby -e 'print ENV["text"]'.
Can this be done in pure shell? I was wondering if env command would take an unresolved var name but it does not seem to.
Same solution as always.
echo "$text"
export TEST="A\nB\nC"
echo $TEST
gives output:
A\nB\nC
but:
echo -e $TEST
A
B
C
So, the answer seems to be the '-e' parameter to echo, assuming that I understand your question correctly.

Escaping in a sh script?

I've got the following line in my script:
xrandr --newmode "$xx$y" $m
where $x and $y are integers, to produce an output like 1024x768.
Unfortunately my script is interpreting the $x as $xx - how can I stop this & get the desired behavior?
You could try to do it this way
"${x}x$y"
Have a look at the docs for more info.
The general logic is to isolate the variable so that it doesn't take xx as the variable name. There are several ways to do that:
Using quotes:
x="xvar";y="yvar"
echo ""$x"x$y"
echo ""$x"x"$y""
echo "$x""x""$y"
echo "$x"x"$y"
Using brace (mentioned by Alberto Zaccagni):
echo "${x}x$y"

Syntax error running command bc under bash 4.1

I have a bash script with the following line. The variables start_time and start_files[$i] are floating point numbers. I want to compare them using the command bc as follows:
result1=$(bc -l <<< $start_time'>='${start_files[$i]})
When I run the script I always receive the following error.
(standard_in) 1: syntax error
I've checked that this error is due to this line. What am I doing wrong? The thing that this happens to me when using bash 4.1, with bash 4.3 runs fine. However I need to run the script with bash 4.1.
The bc command works however the input doesn't work. The variable start_files is read from a file with this command
IFS=, read -r -a start_files <<< $(head -n 1 file.txt)
Basically I want to read all the values from the first line separated by a coma and store them to different positions of the array. However using bash 4.1 all the values end up stored in start_files[0]. How can I solve this? This lines works for bash 4.3
I would suggest that you use double quotes:
result1=$(bc -l <<<"$start_time >= ${start_files[$i]}")
This way, you are echoing a single string to bc, containing your variables.
Are you reading the values from a file with DOS-style line endings perhaps?
$ start_time=$'1.5\r'
$ i=1
$ start_files[$i]=$'2.5\r'
$ bc -l <<< "$start_time >= ${start_files[$i]}"
(standard_in) 1: illegal character: ^M
(standard_in) 1: illegal character: ^M
You may avoid the here-string, add double quotes and remove a $:
result1=$(echo "$start_time >= ${start_files[i]}" | bc -l)
It would help to give the version of bc you're using. I'd guess it's not the same on the two systems. By the way, your error has nothing to do with Bash.
POSIX bc clearly states that a comparison (referred to as relational_expression in POSIX' bc Specification can only appear in a while, for or if construct.
So, first thing you'll try is this:
bc <<< "if($start_time >= ${start_files[$i]}) 1 else 0"
This might not work, as POSIX' bc doesn't allow an else clause in an if statement. (As amazing as it may seem, you read that last sentence correctly).
If your bc is really POSIX stuck up, then you'll have to do some ugly stuff as, e.g.,
bc <<< "ret=0; if($start_time >= ${start_files[$i]}) { ret=1 } ret"
or even something worse (sorry, I don't have a POSIX bc here, so I can't experiment—if someone has one at hand or remembers the syntax off the top of his head, please edit this line with the proper syntax).
Good luck!

Trying to retrieve first 5 characters from string in bash error?

I'm trying to retrieve the first 5 characters from a string and but keep getting a Bad substitution error for the string manipulation line, I have the following lines in my teststring.sh script:
TESTSTRINGONE="MOTEST"
NEWTESTSTRING=${TESTSTRINGONE:0:5}
echo ${NEWTESTSTRING}
I have went over the syntax many times and cant see what im doing wrong
Thanks
Depending on your shell, you may be able to use the following syntax:
expr substr $string $position $length
So for your example:
TESTSTRINGONE="MOTEST"
echo `expr substr ${TESTSTRINGONE} 0 5`
Alternatively,
echo 'MOTEST' | cut -c1-5
or
echo 'MOTEST' | awk '{print substr($0,0,5)}'
echo 'mystring' |cut -c1-5 is an alternative solution to ur problem.
more on unix cut program
Works here:
$ TESTSTRINGONE="MOTEST"
$ NEWTESTSTRING=${TESTSTRINGONE:0:5}
$ echo ${NEWTESTSTRING}
MOTES
What shell are you using?
Substrings with ${variablename:0:5} are a bash feature, not available in basic shells. Are you sure you're running this under bash? Check the shebang line (at the beginning of the script), and make sure it's #!/bin/bash, not #!/bin/sh. And make sure you don't run it with the sh command (i.e. sh scriptname), since that overrides the shebang.
This might work for you:
printf "%.5s" $TESTSTRINGONE
Works in most shells
TESTSTRINGONE="MOTEST"
NEWTESTSTRING=${TESTSTRINGONE%"${TESTSTRINGONE#?????}"}
echo ${NEWTESTSTRING}
# MOTES
echo $TESTSTRINGONE|awk '{print substr($0,0,5)}'
You were so close! Here is the easiest solution: NEWTESTSTRING=$(echo ${TESTSTRINGONE::5})
So for your example:
$ TESTSTRINGONE="MOTEST"
$ NEWTESTSTRING=$(echo ${TESTSTRINGONE::5})
$ echo $NEWTESTSTRING
MOTES
You can try sed if you like -
[jaypal:~/Temp] TESTSTRINGONE="MOTEST"
[jaypal:~/Temp] sed 's/\(.\{5\}\).*/\1/' <<< "$TESTSTRINGONE"
MOTES
That parameter expansion should work (what version of bash do you have?)
Here's another approach:
read -n 5 NEWTESTSTRING <<< "$TESTSTRINGONE"
The original syntax will work with BASH but not with DASH. On debian systems you
might think you are using bash, but maybe dash instead. If /bin/dash/exist then
try temporarily renaming dash to something like no.dash, and then create soft a
link, aka ln -s /bin/bash /bin/dash and see if that fixes the problem.
expr substr $string $position $length
$position starts from 1

Bash printing "\r"

I'm using OS X, and there is no "-e" equivalent.
How can I textually print "\r"?
Is there even a way to do that?
You could use echo $'\r' which is supported by bash
How about:
echo "\\r"
Works for me.
printf '\r'
The printf command in general tends to be better than echo for cases other than very simple ones. It has more capabilities and fewer variations from one implementation to another.
Script:
#!/bin/bash
r=$'\r'
t=$'\t'
echo "${t}${t}1${r}${t}2${r}3"
Output:
3 2 1

Resources