2013-03-05 5 views
23

부동 소수점 변수를 정수와 비교하려고합니다. 이것이 bash와는 최선의 방법이 아니라는 것을 알고 있지만, 내 모든 스크립트는 이미 bash로 작성되었습니다. $ number는 정수가 될 수 있습니다. 50 이하이면, output1을, 다른 모든 변수에 대해서는 다른 변수 k와 함께 출력하고 싶습니다. 이것은 내가 지금까지 가지고있는 것입니다 :bash에서 변수와의 부동 소수점 비교

number=43 
test=$(echo "scale=2; $number/50" | bc -l) 
echo "$test" 
for k in {1..5} 
do 
    if ["$test" -le 1] 
    then echo "output" 

    elif ["$test" -gt $k] 
    then echo "output$k" 
    fi 
done 

테스트를 시도하면 0.43, 첫 번째 루프도 작동하지 않습니다. 나는 그것이 정수와 부동 소수점 비교와 관련이 있다고 생각하지만 작동하게 만들 수는 없다.

내가 누락 된 부분이 있습니까?

추 신 :이 [0.43: command not found은 터미널이 출력합니다.

+0

당신은 또한 단지 KSH로 전환하고 조판 자동 라운드 사용할 수 있습니다. (1993 년부터 유효하다. 잘 작동한다.) –

답변

43

배쉬는 수레를 처리 할 수 ​​없습니다. 대신 bc에 파이프 :

if [ $(echo " $test > $k" | bc) -eq 1 ] 

test 명령 (즉, [가) 전과 당신이 이런 식으로 숫자를 비교하기 때문에 ((...))를 사용하는 것이 더 낫다조차

후 공간이 필요하기 때문에 당신이 비록 볼 수있는 오류는 다음과 같습니다

if (($(bc <<< "$test > $k"))) 

루프의 일부는 다음과 같아야합니다

관계가 거짓이면 관계식은 0으로 평가되고 관계가 참이면 관계형이 1로 평가됩니다 [source]. 그러나 이것은 동작이 GNU bc이고, POSIX compiant가 아닙니다.

+1

또한 bash : [: 1.3 : 정수 표현식은 [] 표현식을 올바르게 포맷했다면 오류가 될 것이다. + 1 @ user000001 –

+0

감사합니다. 그것은 작동합니다. 사소한 질문, 나는 조사하려고 노력하고있다. 첫 번째가 1보다 작거나 같고 다른 하나가 k보다 엄격하게 높기를 원했습니다. $ (bc <<< "$ test <1") == 1) 또는 (($ (bc <<< "$ test <= 1") == 1)))? – user1983400

+0

두 번째 것은 정확합니다. 첫 번째는 다음과 같이 인용 한 내용이 정확할 것입니다 :'(($ bc <<< "$ test <1 && $ test == 1") == 1))'(또한'=='). 'bc'의 부울 표현식에 대한 자세한 내용은 다음을 참조하십시오. http://www.gnu.org/software/bc/manual/html_mono/bc.html#SEC12 – user000001

9

낡은 질문의 종류이지만 추가 답변이 있다고 생각합니다.

더 정밀도가 높은 계산기 (bc 또는 dc) 로의 파이프 연결은 포크와 추가 프로세스가 필요하지만 배율이 내장되어 있지 않기 때문에 추가 프로세스가 필요합니다. 하지만 내장되어있는 것은 printf입니다. 당신이 당신의 숫자, 당신은 "가짜"이 같은 기능으로, 소수점 비교 부동 수 소수 자릿수의 특정 숫자 내에있는 해결할 수있는 경우에 따라서 :

#!/usr/bin/env bash 

function [[[() { 
    local LANG=C lhs rhs 
    printf -v lhs '%07.3f' "$1"; lhs=${lhs/./} 
    printf -v rhs '%07.3f' "$3"; rhs=${rhs/./} 
    case "$2" in 
    -lt) return $((! (10#$lhs < 10#$rhs))) ;; 
    -le) return $((! (10#$lhs <= 10#$rhs))) ;; 
    -eq) return $((! (10#$lhs == 10#$rhs))) ;; 
    -ge) return $((! (10#$lhs >= 10#$rhs))) ;; 
    -gt) return $((! (10#$lhs > 10#$rhs))) ;; 
    esac 
} 

number=${1:-43} 
test=$(dc -e "2k $number 50/p") 
echo "$test" 

for k in {1..5}; do 
    if [[[ "$test" -le 1 ]]]; then 
     echo "output" 
    elif [[[ "$test" -gt "$k" ]]]; then 
     echo "output $k" 
    fi 
done 

몇 가지가 여기 고려해야한다.

  • 나는 [[[이라는 이름을 귀엽게 지정했습니다. 당신이 좋아하는대로 이름을 붙일 수 있습니다. ntest 또는 mynumericcomparison 또는 심지어 [[[입니다.
  • printf은 bash의 내부 기능이므로 경로에 있음에도 불구하고 포크가 들지 않습니다.
  • 약자는 999.999까지의 숫자를 지원합니다. 더 높은 숫자 (또는 더 높은 정밀도)가 필요하면 printf 형식을 조정하십시오.
  • case 문 안의 각 변수의 시작 부분에있는 10#은 0으로 채워진 숫자가 그렇지 않으면 8 진수로 해석 될 수 있기 때문에 10을 기준으로 비교를 강제 실행합니다.

은 참조 : http://mywiki.wooledge.org/BashFAQ/022

+1

꽤 괜찮은 것 같습니다만, 복사기를 위해서'printf' 형식을 좀 더 합리적인 것으로 설정했습니다 (수레가 꽤 길 수 있고 정밀도를 낮게 유지하면이 기능이 더 빨리 수행되지 않습니다). –

관련 문제