यदि कोई आदेश नहीं दिया जाता है तो मैं बैश स्क्रिप्ट में वैकल्पिक तर्क कैसे लिख सकता हूं?


13

मैं उलझन में हूँ कि निम्नलिखित कार्यक्रम के लिए बैश स्क्रिप्ट लिखते समय वैकल्पिक तर्क / झंडे को कैसे शामिल किया जाए:

कार्यक्रम के लिए दो तर्क आवश्यक हैं:

run_program --flag1 <value> --flag2 <value>

हालाँकि, कई वैकल्पिक झंडे हैं:

run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value> 

मैं बैश स्क्रिप्ट को ऐसे चलाना चाहूंगा कि यह उपयोगकर्ता के तर्क ले ले। यदि उपयोगकर्ता क्रम में केवल दो तर्क देते हैं, तो यह होगा:

#!/bin/sh

run_program --flag1 $1 --flag2 $2

लेकिन अगर कोई वैकल्पिक तर्क शामिल हो तो क्या होगा? मुझे लगता है कि यह होगा

if [ --optflag1 "$3" ]; then
    run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi

लेकिन क्या हो अगर $ 4 दिया जाए लेकिन $ 3 नहीं?


getoptsतुम क्या चाहते हो इसके बिना, आप प्रत्येक ध्वज का पता लगाने के लिए स्विच स्टेटमेंट के साथ एक लूप का उपयोग कर सकते हैं, वैकल्पिक या नहीं।
ओरियन

1
का डुप्लीकेट stackoverflow.com/questions/16483119/...
स्टीव

@ के साथ getopts, मुझे प्रत्येक तर्क संयोजन को निर्दिष्ट करने की आवश्यकता होगी? 3 और 4, 3 और 5, 3 और 4 और 5, आदि?
शांझेंगयांग

नहीं, आप बस उन्हें सेट करें यदि आप उन्हें प्राप्त करते हैं, अन्यथा यह रिपोर्ट करता है कि यह नहीं मिला था, इसलिए मूल रूप से आपको बस प्रत्येक विकल्प मिलता है, जो भी क्रम में, और उन्हें किसी भी क्रम में निर्दिष्ट करें, यदि बिल्कुल भी। लेकिन बस बैश मैन पेज पढ़ें, यह सब वहाँ है।
ओरियन

@ मैं क्षमा चाहता हूँ, लेकिन मुझे अभी भी कुछ समझ नहीं आ रहा है getopts। मान लीजिए कि मैं उपयोगकर्ताओं को सभी तर्कों के साथ स्क्रिप्ट को चलाने के लिए मजबूर करता हूं: run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSEजो कि कार्यक्रम को चलाता है program --flag1 VAL --flag2 VAL। यदि आप भागते हैं run_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE, तो कार्यक्रम के रूप में चलेगा program --flag1 VAL --flag2 VAL --optflag2 10। आप इस तरह का व्यवहार कैसे कर सकते हैं getopts?
शांझेंगयांग

जवाबों:


25

यह लेख दो अलग-अलग तरीके दिखाता है - shiftऔर getopts(और दो दृष्टिकोणों के फायदे और नुकसान पर चर्चा करता है)।

साथ shiftमें अपनी स्क्रिप्ट दिखता है $1, निर्णय लेता है क्या कार्रवाई करने के लिए, और फिर कार्यान्वित shift, चलती $2करने के लिए $1, $3करने के लिए $2, आदि

उदाहरण के लिए:

while :; do
    case $1 in
        -a|--flag1) flag1="SET"            
        ;;
        -b|--flag2) flag2="SET"            
        ;;
        -c|--optflag1) optflag1="SET"            
        ;;
        -d|--optflag2) optflag2="SET"            
        ;;
        -e|--optflag3) optflag3="SET"            
        ;;
        *) break
    esac
    shift
done

साथ getoptsआप में (छोटी) के लिए विकल्पों को परिभाषित whileअभिव्यक्ति:

while getopts abcde opt; do
    case $opt in
        a) flag1="SET"
        ;;
        b) flag2="SET"
        ;;
        c) optflag1="SET"
        ;;
        d) optflag2="SET"
        ;;
        e) optflag3="SET"
        ;;
    esac
done

जाहिर है, ये सिर्फ कोड-स्निपेट्स हैं, और मैंने सत्यापन छोड़ दिया है - यह जांचना कि अनिवार्य आर्ग फ्लैग 1 और फ्लैग 2 सेट हैं, आदि।

आप किस दृष्टिकोण का उपयोग करते हैं यह कुछ हद तक स्वाद का मामला है - आप अपनी स्क्रिप्ट को कितना पोर्टेबल चाहते हैं, चाहे आप केवल शॉर्ट (POSIX) विकल्पों के साथ रह सकते हैं या आप लंबे (GNU) विकल्प चाहते हैं, आदि।


मैं आमतौर पर इसके while (( $# ))बजाय करता हूं while :;और अक्सर *मामले में त्रुटि के साथ छोड़ देता
हूं

यह शीर्षक का उत्तर देता है लेकिन प्रश्न का नहीं।

@ यासेन मैंने कल रात को देखा और मेरे जीवन के लिए ऐसा क्यों नहीं कर पाया। आज सुबह यह बहुत स्पष्ट है (और मैंने ओरियन के जवाब को अब भी देखा है)। मैं आज इस उत्तर को बाद में हटा दूंगा (मैं पहले आपकी टिप्पणी को स्वीकार करना चाहता था, और यह करने का सबसे आसान तरीका था)।
जॉन एन

कोई बात नहीं, यह अभी भी एक अच्छा जवाब है, बस सवाल ने इसे चकमा दिया।
जसन

1
एनबी: set -o nounsetपहले समाधान के मामले में अगर कोई पैरामीटर नहीं दिया जाता है, तो गलती हो जाएगी। फिक्स:case ${1:-} in
राफेल

3

एक सरणी का उपयोग करें।

#!/bin/bash

args=( --flag1 "$1" --flag2 "$2" )
[  "x$3" = xFALSE ] ||  args+=( --optflag1 "$3" )
[  "x$4" = xFALSE ] ||  args+=( --optflag2 "$4" )
[  "x$5" = xFALSE ] ||  args+=( --optflag3 "$5" )
[  "x$6" = xFALSE ] ||  args+=( --optflag4 "$6" )
[  "x$7" = xFALSE ] ||  args+=( --optflag5 "$7" )

program_name "${args[@]}"

यह सही ढंग से उन में रिक्त स्थान के साथ तर्कों को संभाल लेगा।

[संपादित करें] मैं मोटे तौर पर eqivalent सिंटैक्स का उपयोग कर रहा था, args=( "${args[@]}" --optflag1 "$3" )लेकिन जी-मैन ने एक बेहतर तरीका सुझाया।


1
आप यह कहकर थोड़ा सुव्यवस्थित कर सकते हैं args+=( --optflag1 "$3" )। आप हमारे संदर्भ कार्य, बाश / POSIX गोले में एक चर को उद्धृत करने में विफल होने के सुरक्षा निहितार्थ के बारे में मेरा जवाब देखना चाहते हैं , जहां मैं इस तकनीक पर चर्चा कर सकता हूं (सशर्त वैकल्पिक तर्क जोड़कर एक सरणी में कमांड लाइन बनाने की)।
जी-मैन का कहना है कि 'मोनिका'

@ जी-मैन थैंक्स, मैंने देखा नहीं था कि डॉक्यूमेंटेशन में, [@]मेरी समस्या को हल करने के लिए मेरे पास पर्याप्त उपकरण था।
जैसन

1

एक शेल स्क्रिप्ट में, तर्क "$ 1", "$ 2", "$ 3" आदि हैं। तर्कों की संख्या $ # है।
यदि आपकी स्क्रिप्ट विकल्पों को नहीं पहचानती है तो आप विकल्प का पता लगाना छोड़ सकते हैं और सभी तर्कों को ऑपरेंड मान सकते हैं।
विकल्पों को पहचानने के लिए गेटटॉप बिल्ट का उपयोग करें


0

यदि आपके इनपुट विकल्प स्थितीय हैं (आप जानते हैं कि वे किन स्थानों पर हैं), और झंडे के साथ निर्दिष्ट नहीं हैं, तो आप जो चाहते हैं वह केवल कमांड लाइन का निर्माण करना है। बस उन सभी के लिए कमांड तर्क तैयार करें:

FLAG1="--flag1 $1"
FLAG2="--flag2 $2"
OPTFLAG1=""
OPTFLAG2=""
OPTFLAG3=""
if [ xFALSE != x"$3" ]; then
   OPTFLAG1="--optflag1 $3"
fi
if [ xFALSE != x"$4" ]; then
   OPTFLAG2="--optflag2 $4"
fi
#the same for other flags

#now just run the program
runprogram $FLAG1 $FLAG2 $OPTFLAG1 $OPTFLAG2 $OPTFLAG3

यदि पैरामीटर निर्दिष्ट नहीं हैं, तो गलाने वाले तार खाली हैं और कुछ भी नहीं में विस्तार किया गया है। ध्यान दें कि अंतिम पंक्ति में, कोई उद्धरण नहीं हैं। ऐसा इसलिए है क्योंकि आप खोल शब्दों में (देने के लिए मानकों को विभाजित करना चाहते है --flag1और $1अपने कार्यक्रम के लिए अलग तर्क के रूप में)। निश्चित रूप से, यह गलत होगा यदि आपके मूल मापदंडों में रिक्त स्थान हैं। यदि आप इसे चला रहे हैं, तो आप इसे छोड़ सकते हैं, लेकिन यदि यह एक सामान्य स्क्रिप्ट है, तो उपयोगकर्ता के साथ रिक्त स्थान के साथ कुछ इनपुट करने पर इसका अप्रत्याशित व्यवहार हो सकता है। इसे संभालने के लिए, आपको कोड को थोड़ा बदसूरत बनाना होगा।

xमें उपसर्ग []परीक्षण मामले में वहाँ है $3या $4खाली है। उस मामले में, पार्टी का विस्तार होगा [ FALSE != $3 ]में [ FALSE != ]जो एक सिंटैक्स त्रुटि है, तो एक और मनमाने ढंग से चरित्र इस से बचने के लिए है। यह एक बहुत ही सामान्य तरीका है, आप इसे कई लिपियों में देखेंगे।

मैंने शुरुआत OPTFLAG1में उन्हें और बाकी को ""सिर्फ यकीन के लिए सेट किया (यदि वे पहले कुछ करने के लिए सेट थे), लेकिन अगर वे वास्तव में पर्यावरण में घोषित नहीं किए गए थे, तो आपको ऐसा करने की सख्त आवश्यकता नहीं है।

अतिरिक्त टिप्पणी की एक जोड़ी:

  • आप वास्तव में मापदंडों को उसी तरह प्राप्त कर सकते हैं जैसे runprogramकि: झंडे के साथ। वही John Nबात कर रहा है। यही कारण है कि जहां है getoptsउपयोगी हो जाता है।
  • उस उद्देश्य के लिए FALSE का उपयोग करना थोड़ा अस्थिर और काफी लंबा है। आमतौर पर, एक -खाली चरित्र को इंगित करने के लिए एक एकल वर्ण (संभवतः ) का उपयोग करेगा , या बस एक रिक्त स्ट्रिंग पास करेगा, जैसे ""कि, अन्यथा यह पैरामीटर का एक वैध मूल्य नहीं है। खाली स्ट्रिंग भी परीक्षण को छोटा बनाती है, बस उपयोग करें if [ -n "$3" ]
  • यदि केवल एक वैकल्पिक ध्वज है, या यदि वे निर्भर हैं, तो आपके पास OPTFLAG2 कभी नहीं हो सकता है, लेकिन OPTFLAG1 नहीं, तो आप बस उन लोगों को छोड़ सकते हैं जिन्हें आप सेट नहीं करना चाहते हैं। यदि आप ""रिक्त मापदंडों के लिए उपयोग करते हैं, जैसा कि ऊपर सुझाया गया है, तो आप वैसे भी सभी अनुगामी खाली छोड़ सकते हैं।

यह विधि बहुत अधिक है जिस तरह से मेकफाइल्स में कंपाइलरों के लिए विकल्प पारित किए जाते हैं।

और फिर से - यदि इनपुट में रिक्त स्थान हो सकते हैं, तो यह बदसूरत हो जाता है।


नहीं, आप शेल को शब्दों में विभाजित नहीं करना चाहते हैं। आपको हमेशा शेल चरों के सभी संदर्भों को उद्धृत करना चाहिए जब तक कि आपके पास कोई अच्छा कारण न हो, और आपको यकीन है कि आप जानते हैं कि आप क्या कर रहे हैं। यदि आप इससे परिचित नहीं हैं, और मेरे उत्तर पर स्क्रॉल करें , जहां मैं इस समस्या को ठीक से हल करता हूं (उसी तकनीक के साथ जैसन का उपयोग करता है ) तो सुरक्षा के निहितार्थ को bash / POSIX गोले में एक चर को उद्धृत करने में विफल देखें ।
जी-मैन का कहना है कि 'मोनिका'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.