쉘 스크립트에서 64비트 정수 처리

쉘 스크립트에서 64비트 정수 처리

이더넷 인터페이스에서 사용되는 대역폭(1000Mbit/s)을 계산하려고 합니다. 내 스크립트를 테스트하기 위해 사용합니다.아이퍼프엄청난 대역폭을 생성하는 도구.

내가 직면하고 있는 문제는 최대 32비트 값보다 큰 값을 언제 어떻게 얻을 수 있느냐는 eth0_rx1것 입니다. eth0_rx2나는 0의 차이를 얻는다.

어떻게든

printf 'eth0 Download rate: %s B/s\n' "$((eth0_rx2-eth0_rx1))"

올바른 값을 제공하지만 사용하려고 하면

eth0_diff=expr $eth0_rx2 - $eth0_rx1

내가 얻는 값은 0이다.

32비트 rx_bytes이상일 경우 처리할 수 있는 방법이 있나요 ?tx_bytes

이것이 사용된 대역폭을 계산하는 우아한 방법인지 잘 모르겠습니다. 그렇지 않다면 다른 대안을 제안해주세요.

예제 출력:

eth0_rx1 = 2134947002 \
eth0_rx2= 2159752166 \
eth0 Download rate: 24805164 B/s \
eth0_diff = 12536645 \
eth0_rx_kB = 12242 \
eth0_rx_kB_100 = 1224200 \
eth0_rx_kB_BW = 9

eth0_rx1 = 2159752166 \
eth0_rx2= 2184557522 \
eth0 Download rate: 24805356 B/s \
eth0_diff = 0 \
eth0_rx_kB = 0 \
eth0_rx_kB_100 = 0 \
eth0_rx_kB_BW = 0

사용된 스크립트:

#!/bin/sh

eth0_rx1=$(cat /sys/class/net/eth0/statistics/rx_bytes)
while sleep 1; do
    eth0_rx2=$(cat /sys/class/net/eth0/statistics/rx_bytes)
    echo "eth0_rx1 = $eth0_rx1"
    echo "eth0_rx2= $eth0_rx2"
    printf 'eth0 Download rate: %s B/s\n' "$((eth0_rx2-eth0_rx1))"

    eth0_diff=`expr $eth0_rx2 - $eth0_rx1`
    echo "eth0_diff = $eth0_diff"

    #convert bytes to Kilo Bytes
    eth0_rx_kB=`expr $eth0_diff / 1024`
    echo "eth0_rx_kB = $eth0_rx_kB"

    #bandwidth calculation
    eth0_rx_kB=`expr $eth0_rx_kB \* 100`
    echo "eth0_rx_kB_100 = $eth0_rx_kB"
    #125000 = 1000 Mbit/s
    eth0_rx_kB=`expr $eth0_rx_kB / 125000`
    echo "eth0_rx_kB_BW = $eth0_rx_kB"

    eth0_rx1=$eth0_rx2
    eth2_rx1=$eth2_rx2
done

답변1

올바른 값이 주어진다고 가정하고 printf 'eth0 Download rate: %s B/s\n' "$((eth0_rx2-eth0_rx1))"정수 연산이 충분하다면 다음과 같은 답을 얻을 수 있습니다 $((eth0_rx2-eth0_rx1)). 쉘 산술.

많은 쉘, 특히 Bash는 다음을 사용합니다.64비트 정수, 32비트 플랫폼에서도 마찬가지입니다.

그러므로:

    eth0_diff=$((eth0_rx2 - eth0_rx1))
...
    eth0_rx_kB=$((eth0_diff / 1024))
...
    eth0_rx_kB=$((eth0_rx_kB * 100))
...
    eth0_rx_kB=$((eth0_rx_kB / 125000))

암소 비슷한 일종의 영양expr 할 수 있는임의의 정밀 연산을 지원합니다.GNU MP 라이브러리로 빌드된 경우. 다른 경우에는 expr시스템에서 크기가 분명히 32비트인 기본 정수를 사용합니다(GNU를 사용한다고 가정). 다른 구현에도 비슷한 제한이 있을 수 있습니다.

답변2

bash64비트 정수를 사용하십시오.

$echo $((2**63-1))
9223372036854775807
$echo $((2**63))
-9223372036854775808

답변3

표준 임의 정밀도 계산기는 입니다 dc. 이를 사용하여 큰 정수 연산을 수행할 수 있습니다.

eth0_diff=$(dc -e "$eth0_rx2 $eth0_rx1 -p")

dc및 명령을 사용하여 인쇄 할 수도 있습니다 .np

#!/bin/sh

set -eu

netstatfile=/sys/class/net/eth0/statistics/rx_bytes
test -r "$netstatfile"

eth0_rx1=$(cat "$netstatfile")

while sleep 1
do
    eth0_rx2=$(cat "$netstatfile")
    dc -e "$eth0_rx1[eth0_rx1 = ]np $eth0_rx2[eth0_rx2 = ]np" \
       -e 'r-[eth0_diff = ]np [Download rate: ]np 1024/[eth0_rx_kB = ]np' \
       -e '100/[eth0_rx_kB_100 = ]np 125000/[eth0_rx_kB_BW = ]np'
    eth0_rx1=$eth0_rx2
done

numfmt도구(GNU coreutils의 일부)는 십진수 또는 이진수 천으로 나누는 데 유용할 수 있습니다. 매우 큰 숫자를 처리할 수 있습니다(물론 여기서 사용되는 이상한 혼합은 아니지만).

관련 정보