$ REPLY가 숫자 범위에 있는지 확인하십시오. “$REPLY” ] ;

비디오 파일을 MP4로 변환하기 위해 Bash를 사용하여 Linux 용 쉘 스크립트를 작성하고 있습니다. 이를 위해 오디오 avconv와 함께 사용 하고 libvorbis있습니다.

내 스크립트 안에 사용자에게 질문이 있습니다.

read -p "- Audio Quality [scale from -2 to 10] ? "
    if [ -n "$REPLY" ] ; then
    ABITRATE="-aq $REPLY"
    fi

내 “ABITRATE”문자열이 최종 avconv명령 줄에 들어갑니다 .

그러나 사용자에게 Kb (킬로 비트) 값으로 해당 질문에 대답하고 libvorbis사용 하는 척도로 변환 할 수있는 기회를 제공하고 싶습니다 . “-2에서 10까지의 척도”는 다음과 같습니다.

Quality Kbit/s  Normalization
-----------------------------
 -2      ~32        y
 -1      ~48        y
  0      ~64        y
  1      ~80        y
  2      ~96        y
  3     ~112        y
  4     ~128        n
  5     ~160        n
  6     ~192        n
  7     ~224        n
  8     ~256        n
  9     ~320        n
 10     ~500        n

$ REPLY가 숫자 범위에 있는지 확인하는 방법을 알고 싶습니다. 예를 들어 스크립트에서 다음과 같은 작업을 수행하려고합니다.

if [ $REPLY is a number between 1 and 32 ] ; then
 REPLY="-2"
elif [ $REPLY is a number between 33 and 48 ] ; then
 REPLY="-1"
fi

이것이 가능합니까 ( ‘물론 예, 어렵지 않아야합니다’라고 말하고 싶지만 사용할 구문을 모르겠습니다)?



답변

[그냥 할 수 있도록 명령 / 쉘 내부 명령, 비교 테스트가 있습니다

if [ "$REPLY" -ge 1 -a "$REPLY" -le 32 ]; then REPLY=-2;
elif [ "$REPLY" -ge 33 -a "$REPLY" -le 48 ]; then REPLY=-1; fi

여기서 -ge더 크거나 같음을 의미합니다. 은 -a“과”논리적이다. 이 [명령은 특수 구문이 아닌 명령 일뿐입니다 (실제로는 test: check out 과 동일 man test). 따라서 공백이 필요합니다. 쓰면 [$REPLY이름이 지정된 명령을 찾아서 [$REPLY실행 하려고 시도 하지만 작동하지 않습니다. 닫는 것도 마찬가지 ]입니다.

편집 : 숫자가 정수인지 테스트하려면 (코드에서 발생할 수있는 경우) 먼저 테스트를 수행하십시오.

if [[ "$REPLY" =~ ^[0-9]+$ ]]; then
   existing code
else echo "$REPLY is not an integer" >&2 && exit 1; fi

물론 이러한 모든 대괄호 표현식은 0 (true) 또는 1 (false)을 반환하며 결합 될 수 있습니다. 모든 것을 동일한 브래킷에 넣을 수있을뿐만 아니라

if [[ "$REPLY" =~ ^[0-9]+$ ]] && [ "$REPLY" -ge 1 -a "$REPLY" -le 32 ]; then ...

또는 비슷한 것.


답변

당신은 간단히 말할 수 있습니다 :

((REPLY>=1 && REPLY<=32)) && REPLY=-2
((REPLY>=33 && REPLY<=48)) && REPLY=-1

매뉴얼 에서 인용 :

((...))

(( expression ))

산술 표현식은 아래에 설명 된 규칙에 따라 평가됩니다 ( 쉘 산술 참조 ). 표현식의 값이 0이 아닌 경우 리턴 상태는 0입니다. 그렇지 않으면 반환 상태는 1입니다. 이것은 정확히

let "expression"

답변

다음과 같이 할 수 있습니다.

#!/usr/bin/env bash
read -p "- Audio Quality [scale from -2 to 10] ? "
if [ -n "$REPLY" ] ; then
    ABITRATE="-aq $REPLY"
fi

echo "You chose : $ABITRATE : $REPLY"
## If 0 < $REPLY < 33 and $REPLY is a number
if [[ "$REPLY" -gt 0 && "$REPLY" -lt 33 && "$REPLY" =~ '^[0-9]$' ]]
then
    echo "GOOD"
else
    echo "BAD"
fi


답변

먼저 입력이 숫자인지 테스트하십시오. 예를 들어, bash 조건식 의 정규식 일치 연산자 사용 :

if [[ $REPLY =~ -?[0-9]+ ]]; then
  echo "Invalid input (not numeric): $REPLY"
  exit 2
fi

숫자 범위를 테스트하려면 두 가지 가능성이 있습니다.

  • -gt의 운영자 조건식 내부 [ … ]또는 [[ … ]]합니다 (조심하십시오 <>운영자가 문자열 비교 수행하지 숫자 값 비교, 그래서 [[ 10 < 9 ]]사실이다);
  • 내부 의 일반적인 산술 연산자 ((…)).

그러므로:

if ((REPLY >= -2 && REPLY <= 10)); then
  : # do nothing -- pass directly to libvorbis
elif ((REPLY <= 24)); then
  echo "Value outside supported range: $REPLY"
  exit 2
elif ((REPLY <= 135)); then
  REPLY=$(((REPLY+8) / 16 - 4))
elif ((REPLY <= 271)); then
  REPLY=$(((REPLY+16) / 32))
elif ((REPLY <= 400)); then
  REPLY=9
elif ((REPLY <= 707)); then
  REPLY=10
else
  echo "Value outside supported range: $REPLY"
  exit 2
fi

(다른 근사 규칙을 사용하고 싶을 수도 있습니다. 선택한 규칙이 여기에 가장 적합한 지 모르겠습니다.)


답변

문자열이 (소수) 숫자인지 정확하게 감지하려면 먼저 십진 정수 숫자를 정의해야합니다. 간단하면서도 완전한 정의는 다음과 같습니다.

선택적 부호 (+ 또는-)와 그 뒤에 18 (유의) 10 진수를 넘지 않는 순서.

그리고이 단계가 필요합니다 :

  1. 10 진수가 아닌 모든 문자 (기호 뒤)를 제거하십시오.
  2. 모든 선택적 선행 0을 제거하십시오. 선행 0은 쉘이 숫자가 8 진이라고 믿게합니다.
  3. 정수의 최대 크기를 18 자리로 제한하십시오. 2 ** 63-1 미만 (최대 64 비트 정수).

하나의 정규 표현식만이 대부분을 수행합니다.

re='^([+-])?0*([0-9]{1,18})$'
[[ $number =~ $re ]] && integer=${BASH_REMATCH[*]:1}

여러 숫자를 처리하는 코드는 다음과 같습니다.

#!/bin/bash
DebugLevel=4     # 1:fatal 2:error 3:warn 4:info 5:debug 6:trace

SayMsg    (){   local a; a=$1; shift ;            # Log level
                [[ $a -le $DebugLevel ]] && printf '%s' "$@" $'\n' >&2 ;
            }
SayError  (){   a=$1; shift; printf '%s' "$@" $'\n' >&2; exit   "$a";   }

parseint  (){   local re # Parse the first argument as an integer or fail
                re='^([+-])?0*([0-9]{1,18})$'
                [[ $1 =~ $re ]] || { SayMsg 4 "Invalid number $1"; return 2; }
                integer=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
                echo "integer=$integer"
             }

while read val; do
    parseint "$val"
    done <<-\_EOT_
    0
    1
    10
    100
    2345
    123456789012345678
    923456789012345678
    999999999999999999
    0000000012345
    +023
    -00045
    -76
    ""
    ''
    a
    abc
    1234567890123456789
    7.23
    -8.17
    1e3
    10+11
    _EOT_

다음과 같이 인쇄됩니다.

integer=0
integer=1
integer=10
integer=100
integer=2345
integer=123456789012345678
integer=923456789012345678
integer=999999999999999999
integer=12345
integer=+23
integer=-45
integer=-76
Invalid number ""
Invalid number ''
Invalid number
Invalid number a
Invalid number abc
Invalid number 1234567890123456789
Invalid number 7.23
Invalid number -8.17
Invalid number 1e3
Invalid number 10+11

수치가 깨끗하고 명확 해지면 유일하게 누락 된 테스트는 값의 범위를 제한하는 것입니다. 이 간단한 몇 줄은 다음을 수행합니다.

(( 1  <= integer && integer <= 32 )) && REPLY="-2"
(( 33 <= integer && integer <= 48 )) && REPLY="-1"


답변