Find the answer to your Linux question:
Results 1 to 8 of 8
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined! jdh239's Avatar
    Join Date
    Sep 2006
    Posts
    74

    Floating point math help with bash


    I am trying to create a script that will gather certain information, and perform some basic calculations; however, it MUST include floating points. Here is my code:
    Code:
    declare -ir bitspeed=$(( `ethtool \`route | grep ^default | awk '{print $NF}'\` | grep -i speed | awk '{print $NF}' | grep -o '[[:digit:]]*'` * 1000 ));
    
    SERVER="myserver"
    readonly rtt=$(ping $SERVER -c 3 | grep rtt | awk -F"=" '{print $2}' | awk -F "/" '{print $2}' | bc -l)
    
    #BDP_CALC=$(echo - | awk '{print  $bitspeed * $rtt}' )
    BDP_CALC=$(( $bitspeed * $rtt  ))
    echo bitspeed: $bitspeed
    echo rtt: $rtt
    echo BDP_CALC: $BDP_CALC
    Results:
    Code:
    ./hugepages_tuning.sh: line 16: 1000000 * 27.604  : syntax error: invalid arithmetic operator (error token is ".604  ")
    bitspeed: 1000000
    rtt: 27.604
    BDP_CALC:
    I am sure there are ways to do this in perl, ruby, python, etc, but I am trying to find a bash-only solution due to the nature of the environment.

  2. #2
    Just Joined! jdh239's Avatar
    Join Date
    Sep 2006
    Posts
    74
    I got it working:
    Code:
    declare -ir bitrate=$(( `ethtool \`route | grep ^default | awk '{print $NF}'\` | grep -i speed | awk '{print $NF}' | grep -o '[[:digit:]]*'` * 1000 ));
    
    SERVER="myserver"
    
    rtt=$(ping $SERVER -c 3 | grep rtt | awk -F"=" '{print $2}' | awk -F "/" '{print $2}' | bc )
    
    BDP_CALC=$(awk "BEGIN {printf \"%.0f\",${bitrate}*${rtt}}")
    
    echo bitrate: $bitrate
    echo rtt: $rtt
    echo BDP_CALC: $BDP_CALC
    exit 0
    Result:

    Code:
    # ./hugepages_tuning.sh
    bitrate: 1000000
    rtt: 28.483
    BDP_CALC: 28483000

  3. #3
    your code: too many pipes.
    a bash oneliner wrapped in a script.

    anyhow, bash cannot do floating point by itself.
    the usual solution is to use 'bc'.
    I am not a "Linux Guru"! Get off me! The Forum software won't let me change it!
    How to ask smart questions | Don't be a Help Vampire
    You can post a link by removing "http://www." from it.

  4. $spacer_open
    $spacer_close
  5. #4
    Just Joined! jdh239's Avatar
    Join Date
    Sep 2006
    Posts
    74
    Quote Originally Posted by nihili View Post
    your code: too many pipes.
    a bash oneliner wrapped in a script.

    anyhow, bash cannot do floating point by itself.
    the usual solution is to use 'bc'.
    How would you write it (without all of the pipes)?

  6. #5
    Quote Originally Posted by jdh239 View Post
    How would you write it (without all of the pipes)?
    haha, a trick question!
    explain what it does and how, i might join in.
    I am not a "Linux Guru"! Get off me! The Forum software won't let me change it!
    How to ask smart questions | Don't be a Help Vampire
    You can post a link by removing "http://www." from it.

  7. #6
    Just Joined! jdh239's Avatar
    Join Date
    Sep 2006
    Posts
    74
    Quote Originally Posted by nihili View Post
    haha, a trick question!
    explain what it does and how, i might join in.
    It finds the interface tied to the default route, runs ethtool against the interface and finds the speed. It puts this into a variable as an int. It also multiplies it by 1000 in preparation of a later calculation.

  8. #7
    Just Joined! jdh239's Avatar
    Join Date
    Sep 2006
    Posts
    74
    Further explanation:
    Code:
    declare -ir bitspeed=$(( `ethtool \`route | grep ^default | awk '{print $NF}'\` | grep -i speed | awk '{print $NF}' | grep -o '[[:digit:]]*'` * 1000 ));
    declare -ir bitspeed
    This defines a variable as an int as read onlly

    ethtool `route | grep ^default | awk '{print $NF}`
    This runs the route command, finds the line that starts with default, and then grabs the last column (the interface). It then runs ethtool against that interface.

    | grep -i speed | awk '{print $NF}' | grep -o '[[:digit:]]*'` * 1000
    This takes the output of the previous command, and finds the line that contains "speed". It grabs the last column which includes digits and letters. The grep -o '[[:digit:]]*' forces it to find only (and all) digits. The *1000 just multiplies it by 1000

  9. #8
    quite the script.

    a thought:

    instead of multiplying the speed by 1000, leave it as it is.
    ping seems to always use 3 digits after the dot, in the averaging in the last line.
    get your value, then just remove the dot, and perform your arithmetics with 2 integers!

    the first monster could probably be replaced by

    Code:
    bitspeed=$(</sys/class/net/$(ip route | awk '/default/ { print $5 }')/speed)
    and the second maybe by
    Code:
    rtt="$(ping $server -c3|tail -1)" 
    rtt="${rtt#*=*/}" 
    rtt="${rtt%%/*}" 
    rtt="${rtt/./}"
    not completely without subshells, but much less, and more simple plain bash.
    I am not a "Linux Guru"! Get off me! The Forum software won't let me change it!
    How to ask smart questions | Don't be a Help Vampire
    You can post a link by removing "http://www." from it.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •