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


30

비디오 파일을 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

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


AFAIK, Vorbis는 MP4 파일에서 유효한 오디오 코덱이 아닙니다 (AAC 또는 MP3를 사용하려는 경우).
evilsoup

감사합니다 .VLC에서 잘 작동했지만 Totem은 그것을 읽고 싶지 않습니다. libvo_aacenc
MrVaykadji로

답변:


30

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

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 ...

또는 비슷한 것.


정확히 내가 찾던 것, 감사합니다! 간단한 비교 표현식을 대신 사용할 수 >=있습니까?
MrVaykadji

Bash는 테스트를 위해 많은 유형의 브래킷을 허용합니다. 이 전통적인 [괄호가 man test있습니다. 이것들은 전통적이고 바보가 아닙니다. 그런 다음 많은 bash 내장이 있습니다. 당신이 [[이 사람이 (이 <=> 평균 문자열 비교 및 정수 비교가에서와 동일한 경로 이름을 확장하지 않는 한, 유사하지만 동일하지한다 [). 두 파일 모두 파일 존재, 권한 등에 대한 많은 테스트를 거쳤습니다. 그런 다음 @devnull의 답변에 single (및 double이 ((사용되었습니다. man bash아래에서 확인하십시오 Compound Commands.
오리온

1
@MrVaykadji 변수가 숫자인지 테스트하는 것이 좋습니다. 그렇지 않으면 예기치 않은 결과가 나타날 수 있습니다.foo='a'; [[ "$foo" -lt 32 ]] && echo yes
terdon

12

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

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

매뉴얼 에서 인용 :

((...))

(( expression ))

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

let "expression"

나는 단순함을 좋아하지만 무엇 ((입니까? 나는 그것들을 신속하게 사용하려고 시도했지만 작동하는 것처럼 보이지만 그것이 if [ ] ; then존재한다는 것을 몰랐습니다.
MrVaykadji

@MrVaykadji 매뉴얼에서 참조를 추가했습니다. 명확하지 않은 경우 알려주십시오.
devnull

1
@MrVaykadji 또한 말하는 if [ condition ]; then foo; fi것은 말하는 것과 같습니다 condition && foo.
devnull

좋아 멋져 ! 가능하다면 당신의 두 가지 아 소르 (Orion과 당신)를 받아들이고 싶습니다. 이 모든 것에 감사드립니다. 나는 많은 것을 배웠습니다.
MrVaykadji

이것을 사용하면 선행 0을 제거 할 수 있습니다. a=08; (( a > 1 ))08은 8 진으로 간주되므로 오류가 발생합니다. 으로 10 진수를 강제 할 수도 있습니다 10#$REPLY. cmd && cmd로 확실히 동일하지 않습니다 if cmd; then ...당신이 필요 일단 else논리적 체인, 부분 &&||미묘한 버그가 발생할 수 있습니다.
llua

4

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

#!/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

2

먼저 입력이 숫자인지 테스트하십시오. 예를 들어, 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

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


1

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

선택적 부호 (+ 또는-)와 그 뒤에 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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.