제1장: The Missing Code Library -- 4. 우아 한 표현 대수

7912 단어 linuxshellbash
프로그래머 가 자주 저 지 르 는 오 류 는 계산 결 과 를 사용자 에 게 표시 할 때 가장 먼저 포맷 하지 않 았 다 는 것 이다.만약 에 사용자 가 오른쪽 에서 왼쪽으로 수 동 으로 계산 한 다음 에 마음 속 에 세 개의 숫자 에 하나의 쉼표 를 삽입 하지 않 으 면 43245435 라 는 숫자 가 백만 에 달 하 는 지 정 하기 어렵다.계산 결 과 를 포맷 하려 면 아래 스 크 립 트 를 사용 하 십시오.
nicenumber.sh
 #!/bin/sh
 # nicenumber.sh --       ,              
 #  DD TD    。   nicenumber.sh,          ,         。
 
 nicenumber()
 {
     #   ,                。
     #              ,        -d   。
 
     integer=$(echo $1 | cut -d. -f1)         #      
     decimal=$(echo $1 | cut -d. -f2)        #      
 
     if [ $decimal != $1 ]; then
         #         ,      
         result="${DD:="."}$decimal"
     fi
 
     thousands=$integer
 
     while [ $thousands -gt 999 ]; do
         remainder=$(($thousands%1000))         # 3        
 
         while [ ${#remainder} -lt 3 ]; do     #     ,   0  
             remainder="0$remainder"
         done
 
         thousands=$(($thousands/1000))         # remainder    ,   
         result="${TD:=","}${remainder}${result}"     #       
     done
 
     nicenum="${thousands}${result}"
     if [ ! -z $2 ]; then
         echo $nicenum
     fi
 }
 
 DD="."     #         ,           
 TD=","     #      ,         
 
 while getopts "d:t:" opt; do     #      getopts   ,    ,    
     case $opt in
         d)DD="$OPTARG";;
         t)TD="$OPTARG";;
     esac
 done
 shift $(($OPTIND-1))
 
 if [ $# -eq 0 ]; then
     echo "Usage: $(basename $0)[-d c] numeric value"
     echo " -d             (     )"
     echo " -t         (     )"
 fi
 
 nicenumber $1 1     #         nicenumber        
 
 exit 0

   스 크 립 트 작업 방법:   이 스 크 립 트 의 핵심 은 nicenumber 함수 의 while 순환 입 니 다.이 함 수 는 수 치 를 얻 은 후, 순환 하여 그것 을 3 개의 최저 유효 비트 숫자 (즉, 다음 쉼표 오른쪽 에 나타 나 는 3 개의 숫자) 와 보존 하 는 수치 로 나 누 었 다.이 어 이들 최저 유효 위 치 는 순 환 을 통 해 처리 된다.
   실행 코드:   이 스 크 립 트 를 실행 하려 면 아주 큰 수 치 를 간단하게 지정 한 다음 스 크 립 트 는 필요 에 따라 기본 값 을 사용 하거나 플래그 위치 에 따라 (- d 또는 - t) 를 지정 하여 소수 구분자 와 천 자리 구분자 를 추가 합 니 다.함수 의 출력 은 숫자 이기 때문에 결 과 는 다음 과 같 습 니 다. echo "Do you really want pay $(nicenumber $price) dollars?"
   실행 결과:
./nicenumber.sh 5894625
 5,894,625
 ./nicenumber.sh 589462532.433
 589,462,532.433
 ./nicenumber.sh -d, -t. 589462532.433
 589.462.532,433
 ./newnicenum.sh 
 Usage: newnicenum.sh [-d c] [-t c] numeric value
  -d             (     )
  -t         (     )

  확장 읽 기:   서로 다른 국가 에서 사용 하 는 소수 구분자 와 천 자리 구분자 가 다 르 기 때문에 표지 위 치 를 늘 려 유연 하 게 지정 해 야 한다.예 를 들 어 독일 과 이탈 리 아 는 - d ',' t ',' 프랑스 는 - d ',' t ',' 스위스 는 4 가지 언어 를 사용 하 는데 그들 은 - d ',' t '를 사용한다.이 예 는 데 드 코드 를 쓰 는 것 보다 유연 한 응용 이 어떻게 좋 은 지 보 여 주 었 기 때문에 이 스 크 립 트 도 구 는 대부분의 국가의 사용자 에 게 충분히 적용 할 수 있 습 니 다.다른 한편, 이 스 크 립 트 는 입력 한 작은 숫자 구분자 들 을 점 번호 로 쓰 고 있 습 니 다. 입력 한 작은 숫자 들 이 서로 다른 구분자 들 을 사용 할 것 으로 예상 된다 면, cut 명령 에서 지정 한 구분자 두 개 를 변경 할 수 있 습 니 다.아래 를 보 세 요:
integer=$(echo $1 | cut "-d$DD" -f1)      #      decimal=$(echo $1 | cut "-d$DD" -f2)      #     

   이렇게 하면 실행 할 수 있 지만, 완전히 다른 소수 구분자 하 나 를 사용 하면 그다지 완벽 하지 않다.더욱 정교 한 해결 방법 은 이 두 줄 코드 앞에서 먼저 테스트 를 통 해 예상 되 는 작은 숫자 구분자 가 사용자 가 요구 하 는 것 을 확보 하 는 것 이다.우 리 는 두 번 째 스 크 립 트 의 사상 을 배 울 수 있 습 니 다. sed 로 모든 숫자 를 삭제 하고 나머지 가 무엇 인지 볼 수 있 습 니 다.
1 seperator="$(echo $1 | sed 's/[[:digit:]]//g')" 2 if [ !-z "$seperator" -a "$seperator" != "$DD"]; then 3   echo "$0: Unknown decimal seperator $seperator encounted." >&2 4   exit 1 5 fi

개인 소감:
   1. cut 의 구분 자 는 - d 옵션 이 고 - f 는 도 메 인 을 말 합 니 다.생각 하 다이것 이 바로 간략화 판이 다.   2. Shell 스 크 립 트 에서 문자열 에 대한 인용 - 따옴표 와 대괄호.   3. getopts: 스 크 립 트 에 전 달 된 명령 행 인 자 를 분석 하 는 가장 강력 한 도구
getopts 는 다음 과 같은 특징 을 가지 고 있 습 니 다.   1. 스 크 립 트 에 전 달 된 모든 인 자 는 앞 에 마이너스 [-] 를 추가 해 야 합 니 다. getopts 는 - 접두사 가 없 는 인 자 를 처리 하지 않 습 니 다.   2. getopts 는 보통 while 순환 에 놓 여 있 는데 이 while 순환 과 표준 while 순환 은 약간 다 르 고 괄호 [] 로 판단 되 지 않 습 니 다.   3. getopts 는 외부 명령 getopt 가 이 스 크 립 트 에서 사용 하 는 getopts 구조 에 대한 설명 을 대체 할 것 입 니 다. d 와 t 는 모두 표지 옵션 으로 여 겨 집 니 다. d 뒤에 사칭 이 있 습 니 다. 이 옵션 은 하나의 매개 변 수 를 가 져 가 야 한 다 는 것 을 설명 합 니 다. 같은 이치 t 입 니 다.
shift $(($OPTIND-1))

위의 문장의 역할 은 매개 변수 포인터 가 한 자 리 를 아래로 이동 하 는 것 이다.shift 는 인 자 를 가 져 갈 수 있 고 인 자 는 이동 하 는 개수 입 니 다.매개 변수 포인터 OPTIND 를 1 로 줄 이 는 것 은 다음 매개 변 수 를 가리 키 는 뜻 입 니 다.이때 $1 은 첫 번 째 비 옵션 인 자 를 가리 키 고 있 습 니 다.그것 을 어떻게 이해 하 는 지 내 가 테스트 하 는 것 을 보 자.
1 ./newnicenum.sh -d. -t 589462532.345 2      3 Usage:  newnicenum.sh  [-d c] [-t c] numeric value4 -d             (     ) 5 -t         (     )"

왜?- t 뒤에 인자 가 하나 도 따라 오지 않 았 기 때문에 getopts 에서 t 뒤의 사칭 을 기억 하 십 니까?그래서 589462532.345 는 t 의 매개 변수 로 여 겨 지고 $1 은 비어 있 습 니 다. 이 디지털 매개 변 수 는 shift 에 의 해 떨 어 졌 기 때 문 입 니 다.그래서 $\# (즉 매개 변수 개수) 는 0 이 고 세 개의 문 구 를 인쇄 합 니 다.
재 테스트:
1 ./newnicenum.sh -d -t, 589462532.345 2      3 ./newnicenum.sh: Unknown decimal seperator . encounted.

왜 그 세 마디 를 인쇄 하지 않 았 습 니까?작은 숫자 구분자 가 점 번호 라 고 생각 하기 때문에 $DD 는 비어 있 습 니 다 ($DD 는 getopts 에서 값 을 부여 하고 비어 있 습 니 다). 둘 이 다 르 기 때문에 Nicenumber 함수 에서 시작 하 는 if 판단 문 에서 - a 뒤의 조건 에 부합 합 니 다.
주: 이상 getopts 에 대한 설명 은 "Advanced Bash - Scripting Guide"를 참고 하 였 습 니 다.
다음 확장 내용 을 모 으 면 최종 스 크 립 트 는 다음 과 같 습 니 다.
#!/bin/sh
 
 nicenumber()
 {
     #   ,                。
     #              ,        -d   。
 
     seperator="$(echo $1 | sed 's/[[:digit:]]//g')"
     if [ ! -z "$seperator" -a "$seperator" != "$DD" ]; then
         echo "$0: Unknown decimal seperator $seperator encounted." >&2
         exit 1
     fi
 
     integer=$(echo $1 | cut "-d$DD" -f1)     #     
     decimal=$(echo $1 | cut "-d$DD" -f2)    #     
 
     if [ $decimal != $1 ]; then
         #         ,      
         result="${DD:="."}$decimal"
     fi
 
     thousands=$integer
 
     while [ $thousands -gt 999 ]; do
         remainder=$(($thousands%1000))         # 3        
 
         while [ ${#remainder} -lt 3 ]; do     #     ,   0  
             remainder="0$remainder"
         done
 
         thousands=$(($thousands/1000))         # remainder    ,   
         result="${TD:=","}${remainder}${result}"  #       ,:=   ,   TD     ,            
     done
 
     nicenum="${thousands}${result}"
     if [ ! -z $2 ]; then
         echo $nicenum
     fi
 }
 
 DD="."     #         ,           
 TD=","     #      ,         
 
 while getopts "d:t:" opt; do     #      getopts   ,    ,    
     case $opt in
         d)DD="$OPTARG";;
         t)TD="$OPTARG";;
     esac
 done
 shift $(($OPTIND-1))
 
 if [ $# -eq 0 ]; then
     echo "Usage: " $(basename $0) " [-d c] [-t c] numeric value"
     echo " -d             (     )"
     echo " -t         (     )"
 fi
 
 nicenumber $1 1     #         nicenumber        
 
 exit 0

좋은 웹페이지 즐겨찾기