Search code examples
bashpipesyntax-errorvariable-assignmentcommand-substitution

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"

Solution

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