bash에서 부동 소수점 나누기를 어떻게 사용합니까?


242

Bash 스크립트에서 두 이미지 너비를 나누려고하지만 bash는 나에게 0 결과를 제공합니다.

RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))

나는 Bash 가이드를 공부 bc했고 인터넷에서 사용 하는 모든 예제에서 사용해야한다는 것을 알고있다 bc. 에echo 내에서 같은 일을 넣어 시도 SCALE했지만 작동하지 않았다.

튜토리얼에서 찾은 예제는 다음과 같습니다.

echo "scale=2; ${userinput}" | bc 

Bash가 어떻게 플로트를 줄 수 0.5있습니까?


9
스크립트에서 부동 소수점 산술을 시도하는 모든 사람에 대한 의견은 스스로에게 물어보십시오. 실제로 부동 소수점 산술이 필요합니까? 때때로 당신은 정말로없이 잘 지낼 수 있습니다. 예를 들어 BashFAQ / 022 의 마지막 부분을 참조하십시오 .
gniourf_gniourf

답변:


242

당신은 할 수 없습니다. bash는 단지 정수를 않습니다; 당신은 해야한다 와 같은 도구에 위임 bc.


8
bc와 같은 도구를 위임하여 RESULT 변수에 답을 넣으려면 어떻게해야합니까?
Medya Gh

2
VAR = $ (echo "scale = 2; $ (($ IMG_WIDTH / $ IMG2_WIDTH))"| bc)와 같은 의미입니까?
Medya Gh

54
@Shevin VAR=$(echo "scale=2; $IMG_WIDTH/$IMG2_WIDTH" | bc)또는 VAR=$(bc <<<"scale=2;$IMG_WIDTH/$IMG2_WIDTH")$ (())없이 (중괄호); 이것은 명령을 실행하기 전에 bash에 의해 확장됩니다
Nahuel Fouilleul

4
사실이지만 awk는 일반적으로 시스템에 이미 설치되어있을 가능성이 높습니다.
CMCDragonkai

9
@NahuelFouilleul 여기에 가장 좋은 답변이 있습니다. 실제로 자체 답변이어야하며 답변으로 수락되었습니다. 이 특정 라인은 매우 유용했습니다 : VAR = $ (bc <<< "scale = 2; $ IMG_WIDTH / $ IMG2_WIDTH")
David

197

당신은 이것을 할 수 있습니다 :

bc <<< 'scale=2; 100/3'
33.33

업데이트 20130926 : 당신은 사용할 수 있습니다 :

bc -l <<< '100/3' # saves a few hits

8
... 그리고 많은 숫자를 추가합니다. 적어도 내 컴퓨터에서는 33.33333333333333333333이 나지만 전자는 33.33입니다.
Andreas Spindler

12
@AndreasSpindler 오래된 게시물의 종류이지만, 누군가 알고 싶다면 scale 명령을 적용하여 변경할 수 있습니다. bc -l <<< 'scale=2; 100/3'
Martie

scale = 0을 사용하여 bash에서 나중에 사용할 정수를 얻으려는 경우 조심하십시오. v1.06.95부터 bc는 어떤 이유로 입력 숫자에 소수 부분이 있으면 스케일 변수를 무시합니다. 어쩌면 이것은 문서에 있지만 찾을 수 없었습니다. echo $ (bc -l <<< 'scale = 0; 1 * 3.3333')
Greg Bell

1
@GregBell 매뉴얼 페이지에 다음 Unless specifically mentioned the scale of the result is the maximum scale of the expressions involved.과 같은 /연산자가 있습니다 :The scale of the result is the value of the variable scale.
psmith

2
@psmith에게 감사합니다. 흥미롭게도 "결과의 스케일은 가변 스케일의 값"이지만 곱하기에는 그렇지 않습니다. 더 좋은 예 : bc <<< 'scale=1; 1*3.00001' 스케일은 어떤 이유로 스케일이 실제로 5입니다. bc <<< 'scale=1; 1/3.000001' 스케일이 1입니다. 흥미롭게도, 1 세트로 바로 나누면 bc <<< 'scale=1; 1*3.00001/1'스케일이 1입니다.
그렉 벨

136

세게 때리다

다른 사람들이 지적했듯이 bash부동 소수점 산술을 지원하지 않지만 소수 자릿수와 같은 고정 소수점 속임수로 위조 할 수는 있습니다 (예 : 두 개의 소수점 이하)

echo $(( 100 * 1 / 3 )) | sed 's/..$/.&/'

산출:

.33

참조 Nilfred의 대답을비슷하지만 더 간결한 접근법에 을 .

대안

언급 bcawk대안 외에도 다음이 있습니다.

절정

clisp -x '(/ 1.0 3)'

정리 된 출력으로 :

clisp --quiet -x '(/ 1.0 3)'

또는 stdin을 통해 :

echo '(/ 1.0 3)' | clisp --quiet | tail -n1

dc

echo 2k 1 3 /p | dc

천재 cli 계산기

echo 1/3.0 | genius

고스트 스크립트

echo 1 3 div = | gs -dNODISPLAY -dQUIET | sed -n '1s/.*>//p' 

gnuplot

echo 'pr 1/3.' | gnuplot

jq

echo 1/3 | jq -nf /dev/stdin

또는:

jq -n 1/3

ksh

echo 'print $(( 1/3. ))' | ksh

루아

lua -e 'print(1/3)'

또는 stdin을 통해 :

echo 'print(1/3)' | lua

맥시마

echo '1/3,numer;' | maxima

정리 된 출력으로 :

echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'

마디

echo 1/3 | node -p

옥타브

echo 1/3 | octave

echo print 1/3 | perl

python2

echo print 1/3. | python2

python3

echo 'print(1/3)' | python3

아르 자형

echo 1/3 | R --no-save

정리 된 출력으로 :

echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'

루비

echo print 1/3.0 | ruby

wcalc

echo 1/3 | wcalc

정리 된 출력으로 :

echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2

zsh

echo 'print $(( 1/3. ))' | zsh

단위

units 1/3

컴팩트 한 출력으로 :

units --co 1/3

다른 출처

Stéphane Chazelas 는 Unix.SX 에서 비슷한 질문에 답변 했습니다.


9
좋은 대답입니다. 질문 후 몇 년 후에 게시되었지만 허용되는 답변이 더 가치가 있다는 것을 알고 있습니다.
Brian Cline

2
zsh를 사용할 수 있다면 Bash 대신 zsh로 스크립트를 작성하는 것이 좋습니다.
Andrea Corbellini

gnuplot
썸업

좋은 목록입니다. 특히 echo 1/3 | node -p짧습니다.
Johnny Wong

39

marvin의 답변을 조금 개선 :

RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")

bc가 항상 설치된 패키지로 제공되는 것은 아닙니다.


4
awk 스크립트 exit는 입력 스트림에서 읽지 못하게합니다. 또한 -v이쑤시개 증후군이 기울어지는 것을 막기 위해 awk의 플래그를 사용하는 것이 좋습니다 . 그래서 :RESULT=$(awk -v dividend="${IMG_WIDTH}" -v divisor="${IMG2_WIDTH}" 'BEGIN {printf "%.2f", dividend/divisor; exit(0)}')
aecolley

2
이 작업을 수행하는 더 어색한 방법은 입력 스트림에서 인수를 읽는 것 RESULT=$(awk '{printf("result= %.2f\n",$1/$2)}' <<<" $IMG_WIDTH $IMG2_WIDTH "입니다.
jmster

1
bcPOSIX의 일부이며 일반적으로 사전 설치됩니다.
fuz

이것은 Windows 7에서 git bash를 사용하여 나를 위해 일했습니다 ... 감사합니다 :)
The Beast

31

-l옵션으로 bc를 사용할 수 있습니다 (L 문자)

RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)

4
-l시스템에를 포함 하지 않으면 bc는 부동 소수점 수학을 수행하지 않습니다.
starbeamrainbowlabs

28

bc의 대안으로 스크립트 내에서 awk를 사용할 수 있습니다.

예를 들면 다음과 같습니다.

echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'

위의 "% .2f"는 소수점 이하 두 자리의 부동 소수점 숫자를 반환하도록 printf 함수에 지시합니다. awk가 올바르게 작동하기 때문에 echo를 사용하여 변수를 필드로 파이프했습니다. "$ 1"및 "$ 2"는 awk에 입력 된 첫 번째 및 두 번째 필드를 나타냅니다.

그리고 다음을 사용하여 결과를 다른 변수로 저장할 수 있습니다.

RESULT = `echo ...`

우수한! 감사. bc가없는 임베디드 환경에 유용합니다. 크로스 컴파일 시간을 절약했습니다.
enthusiasticgeek

19

부동 소수점 수학을 포함한 많은 추가 기능을 갖춘 (거의) bash 수퍼 세트 인 zsh를 사용해 볼 수있는 완벽한 시간입니다. 다음은 zsh의 예제와 같습니다.

% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875

이 게시물은 당신을 도울 수 있습니다 : bash-캐주얼 사용을 위해 zsh로 전환 할 가치가 있습니까?


3
나는 zsh의 열렬한 팬이며 지난 4 년 동안 그것을 사용해 왔지만, 대화 형 사용이 여기에 중점을 둡니다. zsh가 필요한 스크립트는 일반적으로 표준이 아니며 슬프게도 다양하기 때문에 다양한 머신 세트에서 이식성이 떨어집니다.
Brian Cline

17

플로트 이전에는 고정 소수점 논리가 사용 된 시간이었습니다.

IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33

마지막 줄은 bashim입니다 .bash를 사용하지 않는 경우이 코드를 대신 시도하십시오.

IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33

코드의 근거는 다음과 같습니다. 나누기 전에 100을 곱하여 소수점 2 자리를 구합니다.


5

선호하는 변형을 찾았다면 함수로 래핑 할 수도 있습니다.

여기에 bash 함수에 bashism을 래핑하고 있습니다.

짧막 한 농담:

function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}

또는 멀티 라인 :

function div {
  local _d=${3:-2}
  local _n=0000000000
  _n=${_n:0:$_d}
  local _r=$(($1$_n/$2))
  _r=${_r:0:-$_d}.${_r: -$_d}
  echo $_r
}

이제 기능이 있습니다

div <dividend> <divisor> [<precision=2>]

그리고 그것을 사용하십시오

> div 1 2
.50

> div 273 123 5
2.21951

> x=$(div 22 7)
> echo $x
3.14

업데이트 나는 bash에 대한 부동 소수점 숫자로 기본 작업을 제공하는 작은 스크립트를 추가했습니다.

용법:

> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333

그리고 여기 스크립트가 있습니다 :

#!/bin/bash
__op() {
        local z=00000000000000000000000000000000
        local a1=${1%.*}
        local x1=${1//./}
        local n1=$((${#x1}-${#a1}))
        local a2=${2%.*}
        local x2=${2//./}
        local n2=$((${#x2}-${#a2}))
        local n=$n1
        if (($n1 < $n2)); then
                local n=$n2
                x1=$x1${z:0:$(($n2-$n1))}
        fi
        if (($n1 > $n2)); then
                x2=$x2${z:0:$(($n1-$n2))}
        fi
        if [ "$3" == "/" ]; then
                x1=$x1${z:0:$n}
        fi
        local r=$(($x1"$3"$x2))
        local l=$((${#r}-$n))
        if [ "$3" == "*" ]; then
                l=$(($l-$n))
        fi
        echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}

1
local _d=${3:-2}더 간단합니다
KamilCuk

4

실제로 부동 소수점은 아니지만 하나 이상의 결과를 설정하는 것을 원한다면 bc를 한 번 호출합니다 ...

source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')

echo bc radius:$1 area:$a diameter:$d

반지름이 $ 1로 지정된 원의 면적과 직경을 계산합니다.


4

busybox 또는 임베디드 시스템의 일부 컷 다운 버전과 같이 단순히 존재하지 않을 수 있기 때문에 bc를 사용할 수없는 시나리오가 있습니다. 어쨌든 외부 의존성을 제한하는 것은 항상 좋은 일이므로 (숫자)로 나눈 숫자에 항상 0을 더할 수 있습니다. 나누기 출력을 정수로 만듭니다. 해당 정수를 얻은 후에는 문자열로 취급하고 소수점을 오른쪽에서 왼쪽으로 이동하여 10의 거듭 제곱과 같은 횟수만큼 분자에 곱합니다. 이것은 정수만 사용하여 부동 소수점 결과를 얻는 간단한 방법입니다.


1
Busybox조차도 Awk가 있습니다. 아마도 여기에 더 유명한 Awk 대답이 있어야합니다.
tripleee

4

Bash에서는 부동 소수점 나누기를 사용할 수 없지만 고정 소수점 나누기를 사용할 수 있습니다. 정수에 10의 거듭 제곱을 곱한 다음 정수 부분을 나누고 모듈로 연산을 사용하여 분수 부분을 얻으면됩니다. 필요에 따라 반올림합니다.

#!/bin/bash

n=$1
d=$2

# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))

4

나는 그것이 오래되었지만 너무 유혹적이라는 것을 알고 있습니다. 대답은 할 수 없지만 ... 할 수는 있습니다. 이것을 시도하자 :

$IMG_WIDTH=1024
$IMG2_WIDTH=2048

$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))

그런 다음 순수 bash에서 잘린 (하위로 반올림이라고 부르는) 후 2 자리를 얻습니다 (다른 프로세스를 시작할 필요가 없습니다). 물론, 포인트 다음에 한 자리 만 필요하면 10을 곱하고 모듈로 10을하십시오.

이것이하는 일 :

  • 첫 번째 $ ((...))은 정수 나누기를 수행합니다.
  • 두 번째 $ ((...))은 100 배 큰 정수 나누기를 수행하여 본질적으로 2 자리를 점의 왼쪽으로 이동 한 다음 (%)는 모듈로를 수행하여 2 자리 만 가져옵니다.

보너스 트랙 : bc 버전 x 1000은 내 노트북에서 1,8 초가 걸렸고 순수한 배쉬는 0,016 초가 걸렸습니다.


3

bash에서 부동 소수점 계산을 수행하는 방법 :

가장 많이 찬 예 중 하나 와 같이 명령에 " here strings "( <<<) 를 사용하는 대신 맨 페이지 섹션 에서 가장 좋아하는 부동 소수점 예가 있습니다 (참조).bcbcEXAMPLESbcman bc 매뉴얼 페이지 ).

시작하기 전에 pi에 대한 방정식은 다음과 같습니다 pi = 4*atan(1). a()다음은에 대한 bc수학 함수입니다 atan().

  1. 이것은 부동 소수점 계산의 결과를 bash 변수 (이 경우)라는 변수에 저장하는 방법pi 입니다. 참고 scale=10이 경우 10 정밀도의 소수 자릿수를 설정합니다. 이 장소 뒤의 10 진수는 잘립니다 .

    pi=$(echo "scale=10; 4*a(1)" | bc -l)
  2. 이제이 변수의 값을 인쇄하는 단일 코드 행을 가지 echo려면 다음과 같이 후속 명령으로 명령을 끝에 추가하십시오 . 메모 절단을 명하신대로, 10 개 진수 장소 :

    pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi
    3.1415926532
  3. 마지막으로 반올림을하겠습니다. 여기에서 printf함수를 사용하여 소수점 이하 4 자리로 반올림합니다. 참고이 3.14159...지금 라운드 3.1416. 반올림하므로 더 이상 scale=10소수점 이하 10 자리를자를 때 사용할 필요가 없으므로 해당 부분 만 제거하면됩니다. 최종 솔루션은 다음과 같습니다.

    pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi
    3.1416

위의 기술에 대한 또 다른 훌륭한 응용 프로그램 및 데모는 런타임 측정 및 인쇄입니다.

dt_min반올림 0.01666666666...됩니다 0.017.

start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); echo "dt_sec = $dt_sec; dt_min = $dt_min"
dt_sec = 1; dt_min = 0.017

관련 :


1
printf
downvoteit


2

허용 된 답변으로 백분율을 계산하려고하지만 정밀도가 떨어지는 사람들 :

이것을 실행하면 :

echo "scale=2; (100/180) * 180" | bc

당신은 얻을 99.00 은 정밀도를 잃는 것만 .

이 방법으로 실행하면 :

echo "result = (100/180) * 180; scale=2; result / 1" | bc -l

이제 당신은 얻을 99.99 .

인쇄 시점에서만 크기를 조정하기 때문입니다.

여기를 참조 하십시오


1

** bash / shell의 주입 안전 부동 소수점 수학 **

참고 :이 답변의 초점은 bash (또는 다른 쉘)에서 수학을 수행하는 주입 안전 솔루션에 대한 아이디어를 제공하는 것입니다.물론 고급 문자열 처리 등을 수행하기 위해 약간의 조정만으로도 동일하게 사용할 수 있습니다.

제시된 솔루션의 대부분은 외부 데이터 (변수, 파일, 명령 행, 환경 변수)를 사용하여 작은 스크립틀릿을 즉석에서 구성합니다. 외부 입력을 사용하여 악성 코드를 엔진에 주입 할 수 있습니다.

다음은 다양한 언어를 사용하여 기본 수학 계산을 수행 한 결과를 부동 소수점으로 비교 한 것입니다. A + B * 0.1을 부동 소수점으로 계산합니다.

모든 솔루션은 유지 관리가 매우 어려운 동적 스크립틀릿을 만들지 말고 대신 정적 프로그램을 사용하고 매개 변수를 지정된 변수에 전달합니다. 특수 문자로 파라미터를 안전하게 처리하여 코드 삽입 가능성을 줄입니다. 입 / 출력 기능을 제공하지 않는 'BC'는 예외입니다.

예외적으로 'bc'는 입력 / 출력을 제공하지 않으며 모든 데이터는 stdin의 프로그램을 통해 제공되며 모든 출력은 stdout으로 이동합니다. 모든 계산은 샌드 박스에서 실행되며 부작용을 허용하지 않습니다 (파일 열기 등). 이론적으로 주입 설계에 의해 안전합니다!

A=5.2
B=4.3

# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'

# Perl
perl -e '($A,$B) = @ARGV ; print $A + $B * 0.1' "$A" "$B"

# Python 2
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*0.1' "$A" "$B"

# Python 3
python3 -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print(a+b*0.1)' "$A" "$B"

# BC
bc <<< "scale=1 ; $A + $B * 0.1"

임의 인수가있는 python3의 경우 : python3 -c 'import sys ; *a, = map(float, sys.argv[1:]) ; print(a[0] + a[1]*0.1 + a[2])' "$A" "$B""4200.0"==> 4205.63
WiringHarness

0

다음은 awk 명령입니다. -F = field separator == +

echo "2.1+3.1" |  awk -F "+" '{print ($1+$2)}'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.