getopt, getopts या मैन्युअल पार्सिंग - जब मैं छोटे और लंबे दोनों विकल्पों का समर्थन करना चाहता हूं तो क्या उपयोग करना है?


32

वर्तमान में मैं एक Bash स्क्रिप्ट लिख रहा हूं जिसमें निम्नलिखित आवश्यकताएं हैं:

  • यह यूनिक्स / लिनक्स प्लेटफार्मों की एक विस्तृत विविधता पर चलना चाहिए
  • इसे छोटे और (GNU) लंबे विकल्पों का समर्थन करना चाहिए

मुझे पता है कि getoptsपोर्टेबिलिटी के मामले में यह पसंदीदा तरीका होगा लेकिन AFAIK यह लंबे विकल्पों का समर्थन नहीं करता है।

getoptलंबे विकल्पों का समर्थन करता है, लेकिन बैशगाइड इसके खिलाफ दृढ़ता से अनुशंसा करता है:

कभी भी गेटअप (1) का उपयोग न करें। getopt खाली तर्क तार, या एम्बेडेड व्हाट्सएप के साथ तर्क नहीं संभाल सकता है। कृपया भूल जाएं कि यह कभी अस्तित्व में था।

तो, अभी भी मैनुअल पार्सिंग का विकल्प है। यह त्रुटि-प्रवण है, कुछ बॉयलरप्लेट कोड का उत्पादन करता है, और मुझे खुद से त्रुटियों को संभालने की आवश्यकता है (मुझे लगता है getopt(s)कि त्रुटि-हैंडलिंग खुद से करते हैं)।

तो, इस मामले में पसंदीदा विकल्प क्या होगा?


जवाबों:


9

यदि इसे यूनिटी की एक सीमा तक पोर्टेबल होना है, तो आपको POSIX श से चिपकना होगा। और AFAIU वहाँ आप सिर्फ हाथ से रोलिंग तर्क पर कोई विकल्प नहीं है।


25

getoptबनाम getoptsएक धार्मिक मुद्दा लगता है। बैशgetopt में तर्क के खिलाफ के रूप में :

  • वैकल्पिक तर्कों के getoptसाथ एक ज्ञात समस्या को संदर्भित करने के लिए "खाली तर्क तार को संभाल नहीं सकता है " , ऐसा लगता है कि यह बिल्कुल भी समर्थन नहीं करता है (कम से कम बैश 4.2.24 के लिए पढ़ने से )। से :getoptshelp getoptsman getopt

    getopt (3) वैकल्पिक तर्कों के साथ लंबे विकल्पों को पार्स कर सकता है जिन्हें खाली वैकल्पिक तर्क दिया जाता है (लेकिन छोटे विकल्पों के लिए ऐसा नहीं किया जा सकता है)। यह getopt (1) वैकल्पिक तर्कों को मानता है जो खाली हैं जैसे कि वे मौजूद नहीं थे।

मुझे नहीं मालूम कि " getoptव्हॉट्सएप हैंडल नहीं किया जा सकता है " एम्बेडेड व्हाट्सएप के साथ तर्क कहां से आता है, लेकिन आइए इसे जांचते हैं:

  • test.sh:

    #!/usr/bin/env bash
    set -o errexit -o noclobber -o nounset -o pipefail
    params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")"
    eval set -- "$params"
    
    while true
    do
        case "$1" in
            -a|--alpha)
                echo alpha
                shift
                ;;
            -b|--bravo)
                echo "bravo=$2"
                shift 2
                ;;
            -c|--charlie)
                echo charlie
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Not implemented: $1" >&2
                exit 1
                ;;
        esac
    done
  • चलाएँ:

    $ ./test.sh -
    $ ./test.sh -acb '   whitespace   FTW   '
    alpha
    charlie
    bravo=   whitespace   FTW   
    $ ./test.sh -ab '' -c
    alpha
    bravo=
    charlie
    $ ./test.sh --alpha --bravo '   whitespace   FTW   ' --charlie
    alpha
    bravo=   whitespace   FTW   
    charlie

चेक और मेट की तरह लग रहा है, लेकिन मुझे यकीन है कि कोई यह दिखाएगा कि मैंने कैसे वाक्य को पूरी तरह से गलत समझा। बेशक पोर्टेबिलिटी मुद्दा अभी भी खड़ा है; आपको यह तय करना होगा कि किसी पुराने या बिना बैश के प्लेटफार्मों में निवेश करने के लिए कितना समय है। मेरा अपना टिप का उपयोग है YAGNI और KISS केवल उन विशिष्ट प्लेटफार्मों जो आप जानते हैं कि इस्तेमाल किया जा जा रहे हैं के लिए विकसित - दिशा-निर्देश। शेल कोड पोर्टेबिलिटी आमतौर पर 100% तक जाती है क्योंकि विकास का समय अनंत तक जाता है।


11
ओपी ने कई यूनिक्स प्लेटफार्मों के लिए पोर्टेबल होने की आवश्यकता का उल्लेख किया, जबकि getoptआप यहां उद्धृत कर रहे हैं लिनक्स-विशिष्ट। ध्यान दें कि getoptइसका हिस्सा नहीं है bash, यह एक GNU उपयोगिता भी नहीं है और लिनक्स पर उपयोग-लिनेक्स पैकेज के साथ भेज दिया गया है।
स्टीफन चेजलस

2
अधिकांश प्लेटफ़ॉर्म में getoptकेवल लिनक्स AFAIK होता है जो लंबे विकल्पों या तर्कों में रिक्तता का समर्थन करता है। अन्य केवल सिस्टम V सिंटैक्स का समर्थन करेंगे।
स्टीफन चेज़लस

7
getoptएक पारंपरिक कमांड है जो लिनक्स से पहले सिस्टम V से आता है। getoptकभी मानकीकृत नहीं किया गया। पोसिक्स, यूनिक्स या लिनक्स (एलएसबी) में से किसी ने भी कभी भी getoptकमांड को मानकीकृत नहीं किया है । getoptsतीनों में निर्दिष्ट है, लेकिन लंबे विकल्पों के लिए समर्थन के बिना।
स्टीफन चेजालस

1
सिर्फ इस चर्चा को जोड़ने के लिए: यह पारंपरिक नहीं है getopt। यह @ StéphaneChazelas द्वारा संकेत के रूप में linux-utils का स्वाद है। इसमें विरासत विकल्प हैं जो ऊपर वर्णित वाक्यविन्यास को अक्षम कर देंगे, विशेष रूप से मैनपेज में कहा गया है कि "GETOPT_COMPATIBLE बलों को SYNOPSIS में निर्दिष्ट पहले कॉलिंग प्रारूप का उपयोग करने के लिए अपनाया जाता है"। हालाँकि, यदि आप लक्ष्य सिस्टम से उम्मीद कर सकते हैं कि इस पैकेज को स्थापित किया जाए तो यह पूरी तरह से जाने का रास्ता है, क्योंकि मूल गेटटॉप भयानक है और बैश का
गेटअप

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

10

इस POSIX शेल फ़ंक्शन के रूप में यह getopts_long लिखा गया है जिसे आप अपनी स्क्रिप्ट के अंदर एम्बेड कर सकते हैं।

ध्यान दें कि पारंपरिक मोड में नहीं होने पर लिनक्स getopt(से util-linux) सही तरीके से काम करता है और लंबे विकल्पों का समर्थन करता है, लेकिन संभवतः आपके लिए एक विकल्प नहीं है यदि आपको अन्य यूनियनों के पोर्टेबल होने की आवश्यकता है।

Ksh93 ( getopts) और zsh ( zparseopts) के हाल के संस्करणों में लंबे विकल्पों को पार्स करने के लिए अंतर्निहित समर्थन है जो आपके लिए एक विकल्प हो सकता है क्योंकि वे अधिकांश यूनियनों के लिए उपलब्ध हैं (हालांकि अक्सर डिफ़ॉल्ट रूप से स्थापित नहीं होते हैं)।

एक अन्य विकल्प का उपयोग करना होगा perlऔर इसका Getopt::Longमॉड्यूल दोनों ही आजकल अधिकांश यूनियनों पर उपलब्ध होना चाहिए, या तो पूरी स्क्रिप्ट को लिखकर perlया केवल ऑप्शन को पार्सल करने के लिए पर्ल को कॉल करें और निकाली गई जानकारी को शेल में फीड करें। कुछ इस तरह:

parsed_ops=$(
  perl -MGetopt::Long -le '

    @options = (
      "foo=s", "bar", "neg!"
    );

    Getopt::Long::Configure "bundling";
    $q="'\''";
    GetOptions(@options) or exit 1;
    for (map /(\w+)/, @options) {
      eval "\$o=\$opt_$_";
      $o =~ s/$q/$q\\$q$q/g;
      print "opt_$_=$q$o$q"
    }' -- "$@"
) || exit
eval "$parsed_ops"
# and then use $opt_foo, $opt_bar...

देखें perldoc Getopt::Longकि यह क्या कर सकता है और यह अन्य विकल्प पार्सर से कैसे भिन्न है।


2

इस मामले पर हर चर्चा पार्सिंग कोड को मैन्युअल रूप से लिखने के विकल्प पर प्रकाश डालती है - तभी आप कार्यक्षमता और पोर्टेबिलिटी के बारे में सुनिश्चित हो सकते हैं। मैं आपको सलाह देता हूं कि आप आसानी से उपयोग किए जाने वाले ओपन-सोर्स कोड जेनरेटरों द्वारा उत्पन्न और फिर से जेनरेट होने वाले कोड न लिखें। Argbash का उपयोग करें , जिसे आपकी समस्या का निश्चित उत्तर देने के लिए डिज़ाइन किया गया है। यह एक अच्छी तरह से प्रलेखित कोड जनरेटर है जो कमांड-लाइन एप्लिकेशन के रूप में , ऑनलाइन या डॉकर छवि के रूप में उपलब्ध है

मैं बैश पुस्तकालयों के खिलाफ सलाह देता हूं, उनमें से कुछ का उपयोग किया जाता है getopt(जो काफी महत्वहीन है) और यह आपकी स्क्रिप्ट के साथ एक विशाल अपठनीय खोल बूँद को बांधने के लिए एक दर्द है।


0

आप उन getoptप्रणालियों पर उपयोग कर सकते हैं जो इसका समर्थन करते हैं और उन प्रणालियों के लिए एक गिरावट का उपयोग करते हैं जो नहीं करते हैं।

उदाहरण के pure-getoptलिए जीएनयू के लिए ड्रॉप-इन रिप्लेसमेंट होने के लिए शुद्ध बैश में लागू किया गया है getopt

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.