Why am I getting a syntax error in this bash command on parentheses printf and calculator function? - bash

Why am I getting an error with the ( in this line of script?
printf "%.3f\n" "$(bc -l <<< ($sum / $total))"
Error:
solution.sh: command substitution: line 11: syntax error near unexpected token `('
solution.sh: command substitution: line 11: `bc -l <<< ($sum / $total))"'
The desired behavior is to take a numerical variables $sum and $total and perform division on them, then print out the value to 3 decimal points.

It is because bc -l needs input as a single string but ($sum / $total) is unquoted and gets split into more than one word.
You may use:
printf "%.3f\n" "$(bc -l <<< "($sum / $total)")"

Better do it like below. It would be more clear
result=$(bc -l <<< ($sum / $total))
printf "%.3f\n" "$result"

Related

Bash Scripting note running

Given an array of string element, join all the elements of the array with spaces, convert all letters to lowercase and send the result to stdout.
Also have challenges with this "Given an array of strings, count the strings that contain at least one uppercase character and output the result to stdout."
Please any heads-up will be appreciated!
I wrote this for question 1:
#!/bin/bash
var=$(IFS='\n'; echo "$(my_array[*])")
var=$(IFS=''; echo "$((${my_arrary[#]}))")
echo $var | tr '[:upper:]' '[:lower]'
echo "$var" | awk '{print tolower($#)}')
echo result
exit 0
But got error when I ran into error as shown below:
$ bash script.sh
script.sh: line 2: my_array[*]: command not found
0
script.sh: line 6: syntax error near unexpected token `)'
script.sh: line 6: `echo "$var" | awk '{print tolower($#)}')'

Using bc in bash for loop array doesn't calculate first input?

I'm struggling to pass a multi-row array of floating-point numbers through a for loop, have it run a calculation, then define a new variable from the outputs.
Here's a simplified version of my Bash:
inputs=$(echo "12.12
34.34")
New_array=$( for var in "${inputs[#]}"; do
echo "${var}*2"| bc -l;
done )
I would expect the result from echo "$New_array" to be this:
$ echo "$New_array"
24.24
68.68
But I get this?
$ echo "$New_array"
12.12
68.68
Or whilst I've been troubleshooting (e.g. removing the $New_array variable):
(standard_in) 1: syntax error
I believe the problem has something to do with line return being read as an input for the first loop? But the solutions I've tried haven't worked so far.
Where am I going wrong?
This is probably what you are trying to do:
#!/bin/bash
inputs=(12.12 34.34)
for var in "${inputs[#]}"; do
New_array+=("$(bc -l <<< "$var * 2")")
done
printf '%s\n' "${New_array[#]}"
Note that inputs=(12.12 34.34) creates an array named inputs having elements 12.12 and 34.34. New_array+=(...) appends an element (here, the output of the command bc -l <<< "$var * 2") to the array New_array. Alternatively, this could be done at once using printf's implicit loop and mapfile builtin of bash:
mapfile -t New_array < <(printf '%s * 2\n' "${inputs[#]}" | bc -l)
If it is guaranteed that the elements of the array don't contain whitespace and glob characters (this is probably the case here), then this could be an alternative way:
New_array=($(printf '%s * 2\n' "${inputs[#]}" | bc -l))

variable error in bash when doing calculation

I assigned output of piping into a variable, but when I try to use the variable to do math, it won't allow me:
%%bash
cd /data/ref/
grep -v ">" EN | wc -c > ref
cat ref
cd /example/
grep -v ">" SR | wc -l > sample
cat sample
echo $((x= cat sample, y= cat ref, u=x/y, z=u*100))
I get this error:
41858
38986
bash: line 7: x= cat sample, y= cat ref, u=x/y, z=u*100: syntax error in expression (error token is "sample, y= cat ref, u=x/y, z=u*100"
You received that error because you passed an invalid arithmetic expression into a bash arithetic expansion. Only an arithmetic expression is allowed for this place. What you try to do seems like this:
ref="$(grep -v ">" /data/ref/EN | wc -c)"
sample="$(grep -v ">" /example/SR | wc -l)"
# this is only integer division
#u=$(( sample / ref ))
#z=$(( 100 * u ))
# to do math calculations, you can use bc
u=$(bc <<< "scale=2; $sample/$ref")
z=$(bc <<< "scale=2; 100*$u")
printf "%d, %d, %.2f, %.2f\n" "$ref" "$sample" "$u" "$z"
so hopefully you get an output like this:
41858, 38986, 0.93, 93.00
Notes:
There is no need to cd before executing a grep, it accepts the full path with the target filename as an argument. So without changing directory, you can grep various locations.
In order to save the output of your command (which is only a number) you don't need to save it in a file and cat the file. Just use the syntax var=$( ) and var will be assigned the output of this command substitution.
Have in mind that / will result to 0 for the division 38986/41858 because it's the integer division. If you want to do math calculations with decimals, you can see this post for how to do them using bc.
To print anything, use the shell builtin printf. Here the last two numbers are formatted with 2 decimal points.

Solaris - Comment Specific Line from File and Add New One

I haven't worked much with solaris, but I'm supposed to be writing a script that searches for a line in a file, comments it out, and writes the correct line below it.
for i in `cat solarishosts`
do
#print hostname
echo ${i}
#get the line number of the expression after the /; save its value to linenum
linenum="$(ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "awk '/%sugrp ALL=\(user\) lines: /usr/bin/su -, /usr/bin/su - user/a{ print NR; exit }' /usr/local/etc/sudoers")"
#overwrite the line # linenum (overwriting just a to add a comment)
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "sed -n "${linenum}"p <<< "#%sugrp ALL=\(user\) lines: /usr/bin/su -, /usr/bin/su - user""
#use the linenum var to make a newlinenum var , this one being one line down from where the commented text was written
newlinenum=linenum+1
#write the line in quotes # the newlinenum position
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 ${i} "sed -n "${newlinenum}"p <<< "%sugrp ALL=\(ALL\) ALL""
done
I'm getting weird errors :
awk: syntax error near line 1
awk: bailing out near line 1
bash: -c: line 0: syntax error near unexpected token `newline'
bash: -c: line 0: `sed -n p <<< #%sugrp ALL=(user) PASSWD: /usr/bin/su -, /usr/bin/su - user'
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `sed -n linenum+1p <<< %sugrp ALL=(ALL) ALL'
It looks like there's an error with my awk syntax ... but it isn't on line 1? And I'm not sure what the error is
I don't have a newline character anywhere in my first sed line?
In my code I escaped the "(' it's complaining about
That's pretty messy. You don't need to ssh into the box 3 times. Your quoting is a big problem. And you never actually write the changes back to the file.
Try this: build up the remote command and call ssh once:
line='%sugrp ALL=(user) lines: /usr/bin/su -, /usr/bin/su - user'
newline='%sugrp ALL=(ALL) ALL'
file=/usr/local/etc/sudoers
awkcmd='$0 == line {print "#" $0; print new}'
cmd=$(
printf "awk -v line='%s' -v new='%s' '%s' %s > %s.new && mv %s %s.bak && mv %s.new %s" \
"$line" \
"$newline" \
"$awkcmd" \
"$file" "$file" "$file" "$file" "$file" "$file"
)
while read -r host; do
echo "$host"
# perform the remote command
ssh -o ConnectTimeout=1 -o ConnectionAttempts=1 "$host" sh -c "$cmd"
done < solarishosts
I use single quotes as much as possible to reduce the need for backslashes in the constant strings, and all variables are quoted when used.

if conditional in bash giving error

I have a small bash script where I want to get the format of a file.
FILENAME=$1
GET_FILE_FORMAT=`file $FILENAME | grep -i data`
if[[ "$GET_FILE_FORMAT" = *data* ]]
echo "Format Data";
fi
However the output that I get is as follows
./try.bash test.data
./try.bash: line 4: if[[ test.data : data = *data* ]]: No such file or directory
Format Data
./try.bash: line 6: syntax error near unexpected token `fi'
./try.bash: line 6: `fi'
There are a couple of problems here:
You don't have any space after if.
The end of the conditional, i.e. if, isn't indicated.
To fix, say:
if [[ "$GET_FILE_FORMAT" = *data* ]]; then
To prevent getting incorrect information when the file name itself contains the string data, say:
GET_FILE_FORMAT=$(file "${FILENAME}" | awk -F: '{print $NF}')

Resources