जाँच करें कि क्या $ REPLY संख्या में है


30

मैं किसी भी वीडियो-फाइल को MP4 में ट्रांसलेट करने के लिए, Bash का उपयोग करके लिनक्स के लिए एक शेल स्क्रिप्ट लिख रहा हूं। कि के लिए, मैं उपयोग कर रहा हूँ avconvके साथ libvorbisऑडियो के लिए।

मेरी स्क्रिप्ट के अंदर, मेरे पास उपयोगकर्ता के लिए एक प्रश्न है:

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

मेरा "संक्षिप्त" स्ट्रिंग अंतिम 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 या संभवतः एमपी 3 का उपयोग करना चाहते हैं ...)
evilsoup

धन्यवाद, इसने VLC पर अच्छा काम किया लेकिन टोटेम इसे पढ़ना नहीं चाहता है। मैं 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 (ट्रू) या 1 (गलत) पर लौटते हैं और संयुक्त हो सकते हैं। न केवल आप एक ही ब्रैकेट में सब कुछ डाल सकते हैं, आप भी कर सकते हैं

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

या ऐसा ही कुछ।


बिल्कुल वही, जिसकी मुझे तलाश थी, धन्यवाद! क्या मैं इसके बजाय सरल तुलना अभिव्यक्ति की तरह उपयोग कर सकता हूं >=?
श्रीवेकादजी

बैश परीक्षण के लिए कई प्रकार के ब्रैकेट की अनुमति देता है। आपके पास ये पारंपरिक [ब्रैकेट हैं, जो देखने में काम करते हैं man test। ये पारंपरिक और मूर्खतापूर्ण सबूत हैं। फिर, आपके पास बहुत सारे बैश बिलियन हैं। आपके पास [[जो समान हैं, लेकिन बिल्कुल वैसा ही नहीं है, क्योंकि यह एक मार्ग का विस्तार नहीं करता है (वहां, <=> मतलब स्ट्रिंग तुलना, और पूर्णांक तुलना समान हैं [)। दोनों के पास फ़ाइल अस्तित्व, अनुमति आदि के लिए बहुत सारे परीक्षण हैं। तब आपने @ devnull के उत्तर में सिंगल (और डबल का ((उपयोग किया है। के 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 है; अन्यथा वापसी की स्थिति 1. यह बिल्कुल इसके बराबर है

let "expression"

मुझे सादगी पसंद है, लेकिन क्या हैं ((? मैंने उन्हें तुरंत उपयोग करने की कोशिश की और यह काम करने लगता है if [ ] ; thenलेकिन मुझे नहीं पता था कि अस्तित्व में है।
श्रीवेकादजी

@MrVaykadji मैन्युअल से एक संदर्भ जोड़ा गया। मुझे बताएं कि क्या यह स्पष्ट नहीं है।
devnull

1
@MrVaykadji इसके अलावा, कहना कहने if [ condition ]; then foo; fiके बराबर है condition && foo
devnull

ठीक है अच्छा ! अगर मैं कर सकता तो मैं आपके दोनों अश्व (ओरियन और आप) को स्वीकार करना चाहता था। इस सब के लिए बहुत बहुत धन्यवाद, मैंने बहुत कुछ सीखा।
९वी

यदि आप इसका उपयोग करते हैं तो आप अग्रणी शून्य को पट्टी करना चाह सकते हैं। a=08; (( a > 1 ))08 के बाद से त्रुटि को अष्टक माना जाएगा। तुम भी दशमलव के साथ मजबूर कर सकता है 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

पहले, परीक्षण करें कि इनपुट संख्यात्मक है या नहीं। उदाहरण के लिए, बैश सशर्त अभिव्यक्तियों के नियमित अभिव्यक्ति मिलान ऑपरेटर का उपयोग करते हुए :

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 (महत्वपूर्ण) दशमलव अंक नहीं हैं।

और इस कदम की जरूरत है:

  1. उन सभी वर्णों को निकालें जो दशमलव अंक नहीं हैं (संकेत के बाद)।
  2. सभी वैकल्पिक अग्रणी शून्य हटाएं। ज़ीरो को लीड करने से शेल को यह विश्वास हो जाएगा कि संख्या ऑक्टल में है।
  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"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.