开发者

evaluate arithmetic expression passed as argument in awk

How to evaluate arithmetic expression passed as argument in awk?

I have this in a file.

1*2*3
1+2*3

awk should output开发者_运维百科 6, 7, when this file is passed in.


awk(1) is the wrong tool as it doesn't have an eval() function. I suggest modifying the file into input for bc(1) or using shell arithmetic expansion:

while read expr; do
    echo "$(($expr))"
done < file


  1. awk doesn't have eval() funciton
  2. use bc or shell arithmetic expansion both can make it
  3. But, if you use it in hadoop scripts, consider the subprocesses problem

besides, you can try these ways:

  1. Consider to write an expression evaluator in AWK (from archive.org, search for calc3)
  2. Use eval
  3. Use Python's eval function


I know this is awful but we can:

awk '{system(sprintf("awk \"BEGIN {print " $0 "}\""))}'

as pointed out, bc, Python eval, bash $(( )), are better solutions

One last suggestion Perl:

perl -nE 'say eval'


Here's another hack inspired in part by @JJoao's answer, and feedback from @DracoMetallium of Twitter...

#!/usr/bin/env bash


calc() {
  awk 'BEGIN { print '"${@//inf/(2 ** 1024)}"'; }'
}


calc '1/2'
#> 0.5

... this also handles instances of inf being passed via Bash built-ins for search-and-replace, eg...

calc 'inf + inf'
#> inf


calc '-inf + -inf'
#> -inf


calc '-inf + inf'
#> -nan

Which may be useful within one's .bashrc file for quick command-line based calculations.


And for completeness, here's an example how to preform the above in (mostly) pure Awk...

calc.awk

#!/usr/bin/awk -f


function calc(expression) {
  gsub("inf", "(2 ** 1024)", expression)
  system(sprintf("awk \"BEGIN {printf(" expression ")}\""))
}


{
  print calc($0)
}

... as well as examples of usage...

calc.awk <<<'1 /2'
#> 0.5


printf '2*2\nsqrt(9)\n' | calc.awk
#> 4
#> 3


calc.awk <<'EOF'
22 / 7
(1 + sqrt(5)) / 2
EOF
#> 3.14286
#> 1.61803


tee -a 'input-file.txt' 1>'/dev/null' <<'EOF'
1*2*3
1+2*3
EOF


calc.awk input-file.txt
#> 6
#> 7


awk code self-eval :

echo '1*2*3
      1+2*3' | 

mawk '
function eval(_,__,___) { 
     return substr("",
     (___=RS)*(RS="^$")*((__="mawk \47BEGIN { "\
         "printf(\"%.f\","(_)") }\47")|getline _), 
     close(__)^(RS=___)*__)_ 
} 
$++NF = eval($!_)'
1*2*3 6
1+2*3 7

And have non-GMP-enabled variants of awk handle bigints via gawk-gmp :

  echo '9^357' | mawk2 '
  
  function eval(__,_,___) { 
      return substr("",(___=RS) * (RS="^$") * ((_="gawk -Mbe"\
      " \47BEGIN { printf("(__)") }\47")|getline __), close(_)^(RS=___)*_)__

  } $++NF = eval($!_)'
9^357 46192968246584020379055552051071189505164865440669900464
      39030285864012137741835863345354556100224446056419891013
      64348709024164571890111337972631022968123699490725498380
      48619487796915547325757427881925121757649463471671577403
      93732287476951829673979533419257547784348206387576562750
      0451665854873600139914343339972692154903156749530623670508969


As an example, consider what iftop gives you:

Host name                   last 2s   last 10s   last 40s cumulative

   1 10.150.1.1      =>     650B      533B        533B     2.08KB
     85.239.108.20   <=     16.0KB    12.9KB     12.9KB   51.5KB

Let's say you need the 2 up/down lines into one line and calculate KB/B into right byte values (*1024). You could have this:

iftop -i eth1 -ts 10 -Bn|egrep "<|>"| sed 's/^   //g;s/^[1-9]/x/g;s/KB/ 1024/g;s/B/ 1/g' | tr -d '\n'|tr "x" '\n'| grep .| awk '{print $1" "$11" - "$9*$10+$19*$20" "$9*$10" "$19*$20 }'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜