$ REPLYが数値の範囲内にあるかどうかを確認します


30

Bashを使用してLinux用のシェルスクリプトを作成し、ビデオファイルをMP4に変換しています。そのために、私はavconvwith libvorbisfor audio を使用しています。

スクリプト内で、ユーザーに質問があります。

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

これは可能ですか(もちろん「はい、難しいことはない」と言いたいのですが、使用する構文がわかりません)?


私の知る限りでは、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:チェックアウト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
オリオン14年

1
@MrVaykadji私は非常に変数が多数あるテストかどうか、あなたはそれ以外の場合は、予期しない結果を得る可能性がありますも、あなたをお勧めします:foo='a'; [[ "$foo" -lt 32 ]] && echo yes
terdon

12

あなたは単に言うことができます:

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

マニュアルから引用:

((...))

(( expression ))

算術式は、以下で説明する規則に従って評価されます(Shell Arithmeticを参照)。式の値がゼロ以外の場合、戻りステータスは0です。それ以外の場合、戻りステータスは1です。これは、

let "expression"

私はシンプルさが好き((ですが、何ですか?私はそれらをプロンプトで使用しようとしましたが、うまくいくようですif [ ] ; thenが、それが存在することを知りませんでした。
MrVaykadji

@MrVaykadjiマニュアルからの参照を追加しました。明確でない場合は教えてください。
devnull

1
@MrVaykadjiさらに、言うことif [ condition ]; then foo; fiはと言うことと同等condition && fooです。
devnull

分かった。すごい !できればあなたのアスワー(オリオンとあなた)の両方を受け入れたいです。このすべてに感謝し、多くのことを学びました。
MrVaykadji

これを使用する場合、先行ゼロを削除することができます。a=08; (( a > 1 ))08は8進数と見なされるためエラーになります。で10進数を強制することもできます10#$REPLYcmd && 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

数値範囲をテストするには、2つの可能性があります。

  • or 内-gt条件式の演算子(and 演算子は数値比較ではなく文字列比較を行うため、true であることに注意してください);[ … ][[ … ]]<>[[ 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

文字列が(10進数の)数値であるかどうかを正しく検出するには、最初に10進数の整数を定義する必要があります。シンプルでありながら完全な定義は次のとおりです。

オプションの符号(+または-)のシーケンスとそれに続く18(有効)未満の10進数。

そして、次の手順が必要です。

  1. (符号の後の)10進数以外のすべての文字を削除します。
  2. オプションの先行ゼロをすべて削除します。先行ゼロは、シェルに数値が8進数であると信じさせます。
  3. 整数の最大サイズを18桁に制限します。2 ** 63-1未満(最大64ビット整数)。

たった1つの正規表現がそのほとんどを行います:

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.