Perform arithmetic on a number in a pipe - linux

Extremely similar to BASH: how to perform arithmetic on numbers in a pipe
However, that answer relates to several numbers and so uses loops, which seems silly as I only have 1 number
date +%s | echo $((1400000000 - $number)) | ...
Edit: I plan on passing this command to watch, so using shell expansion will not work correctly... I am aware I could just make it its own script, but I want to know if I can just one-line the whole thing

You can use bc to do arithmetic in the shell.
echo "1400000000 - `date +%s`" | bc

echo $((1400000000 - $(date +%s))) | ...

I can't do shell expansion, but instead managed to get a variant of John C's answer working:
date +%s | xargs -I d echo "1400000000 - d" | bc | ...
There are, of course, several other options

Related

eliminate subshells for faster process?

I've read that scripts that are calling for a subshell are slow, which would explain why my script are slow.
for example here, where I'm running a loop that gets an number from an array, is this running a subshell everytime, and can this be solved without using subshells?
mmode=1
modes[1,2]="9,12,18,19,20,30,43,44,45,46,47,48,49"
until [[ -z $kik ]];do
((++mloop))
kik=$(echo ${modes[$mmode,2]} | cut -d "," -f $mloop)
filename=$(basename "$f")
# is all these lines
xcolorall=$((xcolorall+$storednr)
# also triggering
pros2=$(echo "100/$totpix*$xcolorall" | bc -l)
IFS='.' read -r pros5 pros6 <<< "$pros2"
procenthittotal2=$pros5.${pros6:0:2}
#subshells and if,
# is it possible to circumvent it?
#and more of the same code..
done
updated:
the pros2 variable is calculating percent, how many % xcolorall are of totpix and the kik variable is getting a number from the array modes, informing the loop about what color it should count in this loop.
I suspect these are the main hoggers, is there anyway to do this without subshells?
You can replace all the subshells and extern commands shown in your question with bash built-ins.
kik=$(echo ${modes[$mmode,2]} | cut -d "," -f $mloop) can be replaced by
mapfile -d, -t -s$((mloop-1)) -n1 kik <<< "${modes[$mmode,2]}".
If $mmode is constant here, better replace the whole loop with
while IFS=, read -r kik; do ...; done <<< "${modes[$mmode,2]}".
filename=$(basename "$f") can be replaced by
filename=${f##*/} which runs 100 times faster, see benchmark.
pros2=$(echo "100/$totpix*$xcolorall" | bc -l) can be replaced by
(( pros2 = 100 * xcolorall / totpix )) if you don't care for the decimals, or by
precision=2; (( pros = 10**precision * 100 * xcolorall / totpix )); printf -v pros "%0${precision}d" "$pros"; pros="${pros:0: -precision}.${pros: -precision}" if you want 2 decimal places.
Of course you can leave out the last commands (for turning 12345 into 123.45) until you really need the decimal number.
But if speed really matters, write the script in another language. I think awk, perl, or python would be a good match here.

Bash Script: Decimal increments in loop (cannot do) [duplicate]

Here is my script:
d1=0.003
d2=0.0008
d1d2=$((d1 + d2))
mean1=7
mean2=5
meandiff=$((mean1 - mean2))
echo $meandiff
echo $d1d2
But instead of getting my intended output of:
0.0038
2
I am getting the error Invalid Arithmetic Operator, (error token is ".003")?
bash does not support floating-point arithmetic. You need to use an external utility like bc.
# Like everything else in shell, these are strings, not
# floating-point values
d1=0.003
d2=0.0008
# bc parses its input to perform math
d1d2=$(echo "$d1 + $d2" | bc)
# These, too, are strings (not integers)
mean1=7
mean2=5
# $((...)) is a built-in construct that can parse
# its contents as integers; valid identifiers
# are recursively resolved as variables.
meandiff=$((mean1 - mean2))
Another way to calculate floating numbers, is by using AWK rounding capability, for example:
a=502.709672592
b=501.627497268
echo "$a $b" | awk '{print $1 - $2}'
1.08218
In case you do not need floating point precision, you may simply strip off the decimal part.
echo $var | cut -d "." -f 1 | cut -d "," -f 1
cuts the integer part of the value. The reason to use cut twice is to parse integer part in case a regional setting may use dots to separate decimals and some others may use commas.
Edit:
Or, to automate the regional settings one may use locale.
echo $var | cut -d $(locale decimal_point) -f 1
You can change the shell which you are using. If you are executing your script with bash shell bash scriptname.sh try using ksh for your script execution. Bash doesn't support arithmetic operations that involve floating point numbers.
Big shout-out to the bc command - it totally saved my day! It's a simple answer, but it worked like a charm.
a=1.1
b=1.1
echo $a + $b | bc -l
# Output:
2.2
#SUM
sum=$(echo $a + $b | bc -l)
echo $sum
# Output
2.2
bc is a command-line calculator, which allows users to perform mathematical calculations on the terminal.

More convenient way to do arithmetic with program output at the shell?

I usually need to run programs to do some file checking, like say use wc to count the lines of a file and then do some arithmetic with it. Usually the way I do this is just getting the output and then doing the arithmetic by opening a python terminal or whichever software can be used to do so.
If I have to do it many times, then this gets a bit annoying, and I'd like to have some method to take the output directly and do the arithmetic that I want. For instance, one that I like is using perl in the following way, assuming I have to take the output of wc and divide it by 12:
perl -e 'print `wc -l file`/12'
This can be useful but gets annoying after a while. Since this is probably something people need to do all the time, I'd like to know what better faster methods people use to do this fast. I've seen expr might be even better, but I get a syntax error when passing it the output of something bound in ``, like above. So basically the shortest, most efficient way one can do this simple arithmetic in linux terminals from file outputs.
Double parentheses ((...)) perform arithmetic, and with a dollar sign $((...)) you can get the result as a string.
echo $((`wc -l < file` / 12))
echo $(($(wc -l < file) / 12))
You can use variables and they don't need dollar signs. Both var and $var are acceptable:
lines=$(wc -l < file)
echo $((lines / 12))
if ((lines * 42 + 17 > 630)); then
...
fi
So basically I have tested with a code on my bash:
Multiline code:
a=$(echo "hi" | wc -l)
echo $a
b=`expr $a + 2`
echo $b
Which I have changed to one line:
echo `expr $(echo "hi" | wc -l) + 20`
echo "hi" | wc -l is calculating no of lines and is within $() which makes it as one variable and evaluate its value
Then expr takes two arguements here and make sure you to use space before and after the operator and use a backtic(`) to evaluate thi and doing echo finally

Echo output of a piped command

I am trying to just echo a command within my bash script code.
OVERRUN_ERRORS="$ifconfig | egrep -i "RX errors" | awk '{print $7}'"
echo ${OVERRUN_ERRORS}
however it gives me an error and the $7 does not show up in the command. I have to store it in a variable, because I will process the output (OVERRUN_ERRORS) at a later point in time. What's the right syntax for doing this? Thanks.
On Bash Syntax
foo="bar | baz"
...is assigning the string "bar | baz" to the variable named foo; it doesn't run bar | baz as a pipeline. To do that, you want to use command substitution, in either its modern $() syntax or antiquated backtick-based form:
foo="$(bar | baz)"
On Storing Code For Later Execution
Since your intent isn't clear in the question --
The correct way to store code is with a function, whereas the correct way to store output is in a string:
# store code in a function; this also works with pipelines
get_rx_errors() { cat /sys/class/net/"$1"/statistics/rx_errors; }
# store result of calling that function in a string
eth0_errors="$(get_rx_errors eth0)"
sleep 1 # wait a second for demonstration purposes, then...
# compare: echoing the stored value, vs calculating a new value
echo "One second ago, the number of rx errors was ${eth0_errors}"
etho "Right now, it is $(get_rx_errors eth0)"
See BashFAQ #50 for an extended discussion of the pitfalls of storing code in a string, and alternatives to same. Also relevant is BashFAQ #48, which describes in detail the security risks associated with a eval, which is often suggested as a workaround.
On Collecting Interface Error Counts
Don't use ifconfig, or grep, or awk for this at all -- just ask your kernel for the number you want:
#!/bin/bash
for device in /sys/class/net/*; do
[[ -e $device/statistics/rx_errors ]] || continue
rx_errors=$(<"${device}/statistics/rx_errors")
echo "Number of rx_errors for ${device##*/} is $rx_errors"
done
Use $(...) to capture the output of a command, not double quotes.
overrun_errors=$(ifconfig | egrep -i "RX errors" | awk '{print $7}')
Your double quotes around RX errors are a problem. Try;
OVERRUN_ERRORS="$ifconfig | egrep -i 'RX errors' | awk '{print $7}'"
To see the commands as they are executing, you can use
set -v
or
set -x
For example;
set -x
OVERRUN_ERRORS="$ifconfig | egrep -i 'RX errors' | awk '{print $7}'"
set +x

How do I divide in the Linux console?

I have to variables and I want to find the value of one divided by the other. What commands should I use to do this?
In the bash shell, surround arithmetic expressions with $(( ... ))
$ echo $(( 7 / 3 ))
2
Although I think you are limited to integers.
echo 5/2 | bc -l
2.50000000000000000000
this '-l' option in 'bc' allows floating results
Better way is to use "bc", an arbitrary precision calculator.
variable=$(echo "OPTIONS; OPERATIONS" | bc)
ex:
my_var=$(echo "scale=5; $temp_var/100 + $temp_var2" | bc)
where "scale=5" is accuracy.
man bc
comes with several usage examples.
You can use awk which is a utility/language designed for data extraction
e.g. for 1.2/3.4
>echo 1.2 3.4 | awk '{ print $2/$1 }'
0.352941
I still prefer using dc, which is an RPN calculator, so quick session to divide 67 by 18 with 4 digits precision would look like
>dc
4k
67
18/p
3.7222
q
>
Obviously, much more available: man dc
In bash, if you don't need decimals in your division, you can do:
>echo $((5+6))
11
>echo $((10/2))
5
>echo $((10/3))
3
I assume that by Linux console you mean Bash.
If X and Y are your variables, $(($X / $Y)) returns what you ask for.
Example of integer division using bash to divide $a by $b:
echo $((a/b))
Something else you could do using raytrace's answer. You could use the stdout of another shell call using backticks to then do some calculations. For instance I wanted to know the file size of the top 100 lines from a couple of files. The original size from wc -c is in bytes, I want to know kilobytes. Here's what I did:
echo `cat * | head -n 100 | wc -c` / 1024 | bc -l
You should try to use:
echo "scale=4;$variablename/3"|bc
you can also use perl -e
perl -e 'print 67/8'
I also had the same problem. It's easy to divide integer numbers but decimal numbers are not that easy.
if you have 2 numbers like 3.14 and 2.35 and divide the numbers then,
the code will be Division=echo 3.14 / 2.35 | bc
echo "$Division"
the quotes are different. Don't be confused, it's situated just under the esc button on your keyboard.
THE ONLY DIFFERENCE IS THE | bc and also here echo works as an operator for the arithmetic calculations in stead of printing.
So, I had added echo "$Division" for printing the value. Let me know if it works for you. Thank you.

Resources