एक स्क्रिप्ट कैसे लिखनी है जो तर्क के साथ या उसके बिना काम करती है?


13

मेरे पास एक बैश स्क्रिप्ट है जो कुछ इस तरह से है:

#!/bin/bash

if [ $1 = "--test" ] || [ $1 = "-t" ]; then
    echo "Testing..."
    testing="y"

else
    testing="n"
    echo "Not testing."

fi

तो मुझे क्या करना है साथ ही इसे चलाने के नहीं है सक्षम होना चाहते हैं ./script --testया ./script -t, लेकिन यह भी कोई तर्क (बस के साथ ./script), लेकिन मालूम होता है, तो मैं ऐसा वर्तमान कोड के साथ उत्पादन सिर्फ है:

./script: line 3: [: =: unary operator expected
./script: line 3: [: =: unary operator expected
Not testing.

तो मैं इसे कैसे प्रोग्राम करूं ताकि इसे बिना किसी तर्क के चलाने के elseबिना त्रुटि को पूरा किए बिना बस चले? मैं क्या गलत कर रहा हूं?


1
आपको अपने चेक के चारों ओर डबल ब्रैकेट चाहिए। [[]]
टेरेंस


@ अगर आपको उन्हें निशाना बनाना पड़े, तो आपको उनकी ज़रूरत नहीं है, हालांकि आपको उनका इस्तेमाल करना चाहिए।
रुस्लान

जवाबों:


1

शेल स्क्रिप्टिंग में लंबे विकल्पों का उपयोग करने का "उचित तरीका" गेटटॉप यूटिलिटी के माध्यम से है । वहाँ भी गेटअप है जो एक बैश बिल्ट-इन है , लेकिन यह केवल जैसे छोटे विकल्पों की अनुमति देता है -tgetoptउपयोग के कुछ उदाहरण यहां देखे जा सकते हैं

यहां एक स्क्रिप्ट है जो दर्शाती है कि मैं आपके प्रश्न को कैसे देखूंगा। अधिकांश चरणों की व्याख्या को स्क्रिप्ट के भीतर टिप्पणियों के रूप में जोड़ा जाता है।

#!/bin/bash

# GNU getopt allows long options. Letters in -o correspond to
# comma-separated list given in --long.

opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened

set -- $opts # some would prefer using eval set -- "$opts"
# if theres -- as first argument, the script is called without
# option flags
if [ "$1" = "--"  ]; then
    echo "Not testing"
    testing="n"
    # Here we exit, and avoid ever getting to argument parsing loop
    # A more practical case would be to call a function here
    # that performs for no options case
    exit 1
fi

# Although this question asks only for one 
# option flag, the proper use of getopt is with while loop
# That's why it's done so - to show proper form.
while true; do
    case "$1" in
        # spaces are important in the case definition
        -t | --test ) testing="y"; echo "Testing" ;;
    esac
    # Loop will terminate if there's no more  
    # positional parameters to shift
    shift  || break
done

echo "Out of loop"

कुछ सरलीकरण और हटाए गए टिप्पणियों के साथ, इसके लिए संघनित किया जा सकता है:

#!/bin/bash
opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened
set -- $opts    
case "$1" in
    -t | --test ) testing="y"; echo "Testing";;
    --) testing="n"; echo "Not testing";;
esac

16

कई तरीके; दो सबसे स्पष्ट हैं:

  • $1दोहरे उद्धरण चिह्नों में डालें :if [ "$1" = "--test" ]
  • $ # का उपयोग करके तर्कों की संख्या की जाँच करें

बेहतर अभी तक, गेटअप का उपयोग करें।


2
गेटटॉप का उपयोग करने के लिए +1। यही सबसे अच्छा तरीका है।
सेठ

3
एक और आम मुहावरा है [ "x$1" = "x--test" ]कमांड लाइन के तर्कों का फिर से बचाव करना जो कि [कमांड के लिए मान्य ऑपरेटर हैं । (यह एक और कारण है कि क्यों [[ ]]पसंद किया जाता है: यह शेल सिंटैक्स का हिस्सा है, न कि केवल एक बिलिन कमांड।)
पीटर कॉर्ड्स

7

आपको अपने वैरिएबल को यदि इस शर्त के अंदर उद्धृत करना होगा। बदलने के:

if [ $1 = "--test" ] || [ $1 = "-t" ]; then

साथ में:

if [ "$1" = '--test' ] || [ "$1" = '-t' ]; then  

फिर यह काम करेगा:

➜ ~ ./test.sh
परीक्षण नहीं।

हमेशा हमेशा अपने चर को दोगुना करें!


क्या सिंगल-कोट्स आवश्यक हैं या कोई इसके बजाय डबल-कोट्स का उपयोग कर सकता है?

सटीक उत्तर इस बात पर निर्भर करता है कि आप किस शेल का उपयोग कर रहे हैं, लेकिन आपके प्रश्न से मुझे लगता है कि आप बॉर्न-शेल वंशज का उपयोग कर रहे हैं। सिंगल और डबल कोट्स के बीच मुख्य अंतर यह है कि वेरिएबल का विस्तार डबल कोट्स के अंदर होता है, लेकिन सिंगल कोट्स के अंदर नहीं: $ FOO = bar $ echo "$ FOO" बार $ echo '$ FOO' $ FOO (hmm .... can ' t प्रारूप कोड टिप्पणियों में ...)
JayEye

@PranoidPanda आपको एकल उद्धरणों का उपयोग करने की आवश्यकता नहीं है, नहीं, लेकिन स्ट्रिंग शाब्दिकों पर उनका उपयोग करना अच्छा है। इस तरह आप बाद में आश्चर्यचकित नहीं होंगे यदि आपके स्ट्रिंग डेटा में एक प्रतीक बैश है जो विस्तार करना चाहता है।
सेठ

@ParanoidPanda @JayEye ने क्या कहा: एकल उद्धरणों के साथ आउटपुट में कोई चर विस्तार foo=bar echo '$foo'प्रिंट नहीं $fooहोता है, बल्कि foo=bar echo "$foo"प्रिंट होता है bar
इकोन्स

4

आप बैश का उपयोग कर रहे हैं। बैश के लिए एक बढ़िया विकल्प है [: [[। इसके साथ [[, आपको यह चिंता करने की ज़रूरत नहीं है कि क्या उद्धृत करने के बारे में है, और आपको इसके लिए [उचित समर्थन सहित बहुत अधिक ऑपरेटर मिलते हैं ||:

if [[ $1 = "--test" || $1 = "-t" ]]
then
    echo "Testing..."
    testing="y"
else
    testing="n"
    echo "Not testing."
fi

या आप नियमित अभिव्यक्ति का उपयोग कर सकते हैं:

if [[ $1 =~ ^(--test|-t) ]]
then
    echo "Testing..."
    testing="y"
else
    testing="n"
    echo "Not testing."
fi

बेशक, उचित उद्धरण हमेशा किया जाना चाहिए, लेकिन [बैश का उपयोग करते समय छड़ी करने का कोई कारण नहीं है ।


3

यह जांचने के लिए कि क्या तर्क मौजूद हैं (सामान्य रूप से, और तदनुसार कार्य करें) यह काम करना चाहिए:

#!/bin/bash

check=$1

if [ -z "$check" ]; then
  echo "no arguments"
else echo "there was an argument"
fi

क्यों नहीं [ -z "$1" ]?
इकोन्स

@ ΥριΈνσταντόποςλο this इस मामले में, निश्चित रूप से, आमतौर पर लिपियों में हालांकि, मैं चर को एक बार कॉल करता हूं, इसे प्रक्रियाओं में संदर्भित करता हूं, जो आमतौर पर एक बार फिर अधिक होता है। नमूने में प्रोटोकॉल रखने का निर्णय लिया गया।
जैकब व्लिजम

इस नमूने में आप $checkकिसी भी shifts से पहले एक बार उपयोग करना चाहते हैं, इसलिए इसका उपयोग करना बेहतर होगा $1
इकोन्स

@ ΥριΈνσταντόποςλο course बेशक, जैसा कि उल्लेख किया गया है, यह एक नमूना है , जिसका उपयोग लिपियों में किया जाना है। लिपियों में, बार-बार एक ही तरह से बार-बार करना बुरा व्यवहार है।
जैकब व्लिजम

मैं समझता हूं कि आपका क्या मतलब है, लेकिन #!नमूने प्रदान करते समय शेबंग का उपयोग नहीं करना बेहतर अभ्यास है (आपको कोड के बाहर शेल का वर्णन करना चाहिए)।
इकोन्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.