দীর্ঘ এবং সংক্ষিপ্ত কমান্ড লাইন বিকল্পগুলি প্রক্রিয়া করার জন্য গোটপটস ব্যবহার করে


410

আমি আমার শেল স্ক্রিপ্টটি ব্যবহার করে কমান্ড লাইন বিকল্পগুলির দীর্ঘ এবং সংক্ষিপ্ত রূপগুলি চালু করতে চাই।

আমি জানি যে getoptsএটি ব্যবহার করা যেতে পারে তবে পার্লের মতো শেল দিয়েও আমি এটি করতে পারিনি।

এটি কীভাবে করা যায় সে সম্পর্কে কোনও ধারণা, যাতে আমি এর মতো বিকল্পগুলি ব্যবহার করতে পারি:

./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/

উপরের দিক থেকে, দুটি কমান্ডই আমার শেলের একই অর্থ বোঝায়, কিন্তু ব্যবহার করে getopts, আমি এগুলি প্রয়োগ করতে সক্ষম হইনি?


2
আইএমএইচও, গৃহীত উত্তরটি সেরা নয়। এটি "আরভিড রিকোয়েস্ট হিসাবে প্রদর্শিত হিসাবে" - "এবং" - "উভয় যুক্তি হ্যান্ডেল করার জন্য কীভাবে কীটপটগুলি ব্যবহার করবেন তা দেখায় না। আমি অনুরূপ ধারণাটি ব্যবহার করে অন্য একটি উত্তর সন্নিবেশ করছি, তবে প্রয়োজনীয় যুক্তিগুলির জন্য মানগুলি সন্নিবেশ করতে "ভুলে যাওয়া" এর ব্যবহারকারীর ত্রুটির সাথেও ডিল করি। মূল বক্তব্য: গিওপটগুলি কাজ করা যায়। ক্রস-প্ল্যাটফর্মের বহনযোগ্যতার প্রয়োজন হলে পরিবর্তে ব্যবহারকারীর "getopt" ব্যবহার করা উচিত। এছাড়াও, গিওপটগুলি শাঁসের জন্য পসিক্স স্ট্যান্ডার্ডের একটি অংশ, তাই এটি বহনযোগ্য হওয়ার সম্ভাবনা রয়েছে।
pauljohn32

উত্তর:


304

এখানে তিনটি বাস্তবায়ন বিবেচনা করা যেতে পারে:

  • ব্যাশ builtin getopts। এটি ডাবল-ড্যাশ উপসর্গ সহ দীর্ঘ বিকল্পের নামগুলি সমর্থন করে না। এটি কেবল একক-অক্ষর বিকল্পগুলি সমর্থন করে।

  • বিএসডি ইউনিক্স স্ট্যান্ডেলোন getoptকমান্ড প্রয়োগ (যা ম্যাকোস ব্যবহার করে)। এটি দীর্ঘ বিকল্পগুলি সমর্থন করে না।

  • একক এর GNU বাস্তবায়ন getopt। জিএনইউ getopt(3)( getopt(1)লিনাক্সের কমান্ড-লাইন দ্বারা ব্যবহৃত ) দীর্ঘ বিকল্পগুলি পার্সিং সমর্থন করে।


getoptsদীর্ঘ কিছু বিকল্পগুলি নকল করতে ব্যাশ বিল্টিন ব্যবহারের জন্য আরও কিছু উত্তর সলিউশন দেখায় । এই সমাধানটি আসলে একটি সংক্ষিপ্ত বিকল্প তৈরি করে যার চরিত্রটি "-"। সুতরাং আপনি পতাকা হিসাবে "-" পান। তারপরে যে কোনও কিছুই এর পরে ওপ্টারগ হয়ে যায় এবং আপনি নেস্টেডের সাথে অপটারকে পরীক্ষা করেন case

এটি চতুর, তবে এটি সাবধানতা সহ আসে:

  • getoptsঅপ্ট স্পেক প্রয়োগ করতে পারে না। যদি ব্যবহারকারী কোনও অবৈধ বিকল্প সরবরাহ করে তবে এটি ত্রুটিগুলি ফিরিয়ে দিতে পারে না। অপ্টগারকে পার্স করার সময় আপনাকে নিজের ত্রুটি-পরীক্ষা করতে হবে।
  • অপ্টগার্গটি দীর্ঘ বিকল্পের নামের জন্য ব্যবহৃত হয়, যখন আপনার দীর্ঘ বিকল্পটিতে নিজেই একটি যুক্তি থাকে তখন ব্যবহার জটিল করে তোলে। আপনার নিজের অতিরিক্ত কোড হিসাবে কোড করতে হবে।

সুতরাং লম্বা বিকল্পগুলির পক্ষে সমর্থনগুলির অভাবের আশেপাশে কাজ করার জন্য আরও কোড লেখা সম্ভব হলেও এটি অনেক বেশি কাজ এবং আপনার কোডটি সহজ করার জন্য একটি গিওপ্ট পার্সার ব্যবহারের উদ্দেশ্যটিকে আংশিকভাবে পরাস্ত করে।


17
So. ক্রস প্ল্যাটফর্ম, পোর্টেবল সমাধান কী?
troelskn

6
জিএনইউ গেটপটকে একমাত্র পছন্দ বলে মনে হচ্ছে। ম্যাকে, ম্যাকপোর্টগুলি থেকে জিএনইউ গিওপট ইনস্টল করুন। উইন্ডোজে, আমি সাইগউইনের সাথে জিএনইউ গিওপট ইনস্টল করব।
বিল কারভিন

2
স্পষ্টতই , ksh getopts দীর্ঘ বিকল্পগুলি পরিচালনা করতে পারে।
টিজিআর

1
@ বিল +1, যদিও ম্যাকের উত্স ( সফটওয়্যার.ফ্রোডো.লুইজার্ড.নেম / গেজেট ) থেকে গোটপট তৈরি করা মোটামুটি সহজ । আপনি "getopt -T; প্রতিধ্বনি $?" দিয়ে স্ক্রিপ্টগুলির মধ্যে থেকে আপনার সিস্টেমে ইনস্টল করা getopt এর সংস্করণটিও দেখতে পারেন।
চিনাসৌর

8
@ বিল কারভিন: "ব্যাশ গেটোপ্টস বিল্ট ইন বিকল্পগুলির নামগুলি ডাবল ড্যাশ উপসর্গ সহ সমর্থন করে না" " তবে ল্যাপ বিকল্পগুলি সমর্থন করার জন্য গিওপটগুলি তৈরি করা যেতে পারে: নীচে stackoverflow.com/a/7680682/915044 দেখুন।
টমরোচে

305

getoptএবং getoptsবিভিন্ন প্রাণী এবং লোকেরা তাদের কাজগুলি সম্পর্কে কিছুটা ভুল বোঝাবুঝি করে বলে মনে হয়। একটি লুপে কমান্ড-লাইন বিকল্পগুলি প্রক্রিয়া করতে এবং অন্তর্নির্মিত ভেরিয়েবলগুলির পরিবর্তে প্রতিটি পাওয়া বিকল্প এবং মান নির্ধারণের getoptsজন্য একটি অন্তর্নির্মিত bashকমান্ড। getoptতবে, এটি একটি বাহ্যিক ইউটিলিটি প্রোগ্রাম, এবং এটি আসলে আপনার বিকল্পগুলি যেমন b যেমন বাশ getopts, পার্ল Getoptমডিউল বা পাইথন optparse/ argparseমডিউলগুলি করে সেগুলি আপনার জন্য প্রক্রিয়া করে না । যা যা করা হয় getoptতা হ'ল বিকল্পগুলি যা পাস করেছে - অর্থাত্ তাদের আরও একটি স্ট্যান্ডার্ড আকারে রূপান্তরিত করে, যাতে শেল স্ক্রিপ্টের জন্য তাদের প্রক্রিয়াটি সহজ হয়। উদাহরণস্বরূপ, একটি অ্যাপ্লিকেশন getoptনিম্নলিখিত রূপান্তর করতে পারে:

myscript -ab infile.txt -ooutfile.txt

এটিতে:

myscript -a -b -o outfile.txt infile.txt

আপনাকে প্রকৃত প্রসেসিং নিজেই করতে হবে। আপনি getoptবিকল্পগুলি নির্দিষ্ট করতে পারেন এমন পথে বিভিন্ন বিধিনিষেধ তৈরি করলে আপনাকে মোটেই ব্যবহার করতে হবে না:

  • যুক্তি অনুযায়ী কেবল একটি বিকল্প রাখুন;
  • সমস্ত বিকল্প কোনও অবস্থানগত পরামিতিগুলির আগে চলে যায় (অর্থাত্ অপশন বিকল্প নয়);
  • মান সহ বিকল্পগুলির জন্য (উদাহরণস্বরূপ -oউপরে) মানটি পৃথক যুক্তি হিসাবে (একটি স্থানের পরে) হিসাবে যেতে হবে।

এর getoptপরিবর্তে কেন ব্যবহার করবেন getopts? মূল কারণ হ'ল কেবল জিএনইউ getoptআপনাকে দীর্ঘ-নামক কমান্ড-লাইন বিকল্পের জন্য সমর্থন দেয়। 1 (গনুহ getopt। লিনাক্স Mac OS X এর সংস্করণ এবং FreeBSD ডিফল্ট মৌলিক এবং-খুব-দরকারী সঙ্গে আসা হয় getopt, কিন্তু গনুহ সংস্করণ ইনস্টল করা যেতে পারে;। নিচে দেখুন)

উদাহরণস্বরূপ, getoptআমার নামক স্ক্রিপ্ট থেকে জিএনইউ ব্যবহারের উদাহরণ এখানে রয়েছে javawrap:

# NOTE: This requires GNU getopt.  On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
             -n 'javawrap' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
  case "$1" in
    -v | --verbose ) VERBOSE=true; shift ;;
    -d | --debug ) DEBUG=true; shift ;;
    -m | --memory ) MEMORY="$2"; shift 2 ;;
    --debugfile ) DEBUGFILE="$2"; shift 2 ;;
    --minheap )
      JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
    --maxheap )
      JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

এটি আপনাকে পছন্দ --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"বা অনুরূপ বিকল্পগুলি নির্দিষ্ট করতে দেয় । কল করার প্রভাবটি getoptবিকল্পগুলিকে আকাঙ্ক্ষিত করে তোলা --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"যাতে আপনি আরও সহজেই এগুলি প্রক্রিয়া করতে পারেন। চারপাশের উদ্ধৃতিগুলি গুরুত্বপূর্ণ "$1"এবং "$2"এটি গুরুত্বপূর্ণ যেহেতু এটি নিশ্চিত করে যে তাদের স্পেসগুলির সাথে যুক্তিগুলি সঠিকভাবে পরিচালনা করা হবে।

যদি আপনি প্রথম 9 টি লাইন মুছে ফেলেন ( eval setলাইনটি দিয়ে সমস্ত কিছু ), কোডটি এখনও কাজ করবে ! যাইহোক, আপনার কোডটি কী ধরণের বিকল্পগুলি গ্রহণ করবে সে সম্পর্কে এটি অনেক বেশি পছন্দসই হবে: বিশেষত, আপনাকে উপরে বর্ণিত "প্রচলিত" ফর্মটিতে সমস্ত বিকল্প নির্দিষ্ট করতে হবে। getoptতবে এর ব্যবহারের সাহায্যে আপনি একক-বর্ণের বিকল্পগুলি গোষ্ঠীভুক্ত করতে পারেন, দীর্ঘ-বিকল্পগুলির সংক্ষিপ্ত অ-দ্ব্যর্থক ফর্মগুলি ব্যবহার করতে পারেন, হয় --file foo.txtবা --file=foo.txtশৈলীটি ব্যবহার করতে পারেন, হয় -m 4096বা -m4096শৈলীটি ব্যবহার করতে পারেন , মিশ্রণ বিকল্পগুলি এবং কোনও ক্রমে নন-বিকল্পগুলি ইত্যাদি getoptঅজানা বা অস্পষ্ট বিকল্পগুলি পাওয়া গেলে একটি ত্রুটি বার্তা আউটপুট দেয়।

দ্রষ্টব্য : দুটি বৈশিষ্ট্য এবং বিভিন্ন কলিং কনভেনশন সহ বেসিক এবং জিএনইউ এর দুটি সম্পূর্ণ ভিন্ন সংস্করণ রয়েছে। 2 বেসিকটি বেশ নষ্ট হয়েছে: এটি কেবল দীর্ঘ বিকল্পগুলি পরিচালনা করে না এটি আর্গুমেন্ট বা খালি যুক্তির অভ্যন্তরে এম্বেড করা স্থানগুলিও পরিচালনা করতে পারে না, যেখানে এটি সঠিকভাবে করে। উপরের কোডটি বেসিকটিতে কাজ করবে না । জিএনইউ লিনাক্সে ডিফল্টরূপে ইনস্টল করা আছে তবে ম্যাক ওএস এক্স এবং ফ্রিবিএসডি-তে এটি পৃথকভাবে ইনস্টল করা দরকার। ম্যাক ওএস এক্সে ম্যাকপোর্টস ( http://www.macport.org ) ইনস্টল করুন এবং তারপরে জিএনইউ ইনস্টল করতে হবে (সাধারণত এর মধ্যে ), এবং আপনার শেলপথটি সামনে রয়েছে কিনা তা নিশ্চিত করুনgetoptgetoptgetoptgetoptgetoptsgetoptgetoptsudo port install getoptgetopt/opt/local/bin/opt/local/bin/usr/bin। ফ্রিবিএসডি-তে ইনস্টল করুন misc/getopt

আপনার নিজের প্রোগ্রামের জন্য উদাহরণ কোডটি সংশোধন করার জন্য একটি দ্রুত গাইড: প্রথম কয়েকটি লাইনগুলির মধ্যে সমস্তগুলি "বয়লারপ্লেট" যা একই লাইনে থাকবে, কল করা লাইনটি বাদে getopt। আপনার পরে প্রোগ্রামটির নাম পরিবর্তন করা উচিত -n, এর পরে সংক্ষিপ্ত বিকল্পগুলি -oএবং তার পরে দীর্ঘ বিকল্পগুলি নির্দিষ্ট করা উচিত --long। একটি মান নেয় এমন বিকল্পগুলির পরে একটি কোলন রাখুন।

অবশেষে, আপনি যদি ঠিক এর setপরিবর্তে কোডটি দেখতে পান তবে eval setএটি BSD এর জন্য লেখা হয়েছিল getopteval setস্টাইলটি ব্যবহার করতে আপনার এটিকে পরিবর্তন করা উচিত , যা উভয় সংস্করণের সাথেই দুর্দান্ত কাজ করে getopt, যখন setসমভূমিটি GNU এর সাথে সঠিকভাবে কাজ করে না getopt

1 বাস্তবিক, getoptsksh93সমর্থন দীর্ঘ নামে অপশন, কিন্তু এই শেল প্রায়ই হিসাবে হিসাবে ব্যবহার করা হয় না bash। ইন zsh, zparseoptsএই কার্যকারিতা পেতে ব্যবহার করুন ।

2 প্রযুক্তিগতভাবে, "জিএনইউ getopt" একটি ভুল নাম; এই সংস্করণটি আসলে জিএনইউ প্রকল্পের চেয়ে লিনাক্সের জন্য লেখা হয়েছিল। তবে, এটি সমস্ত জিএনইউ কনভেনশন অনুসরণ করে এবং "জিএনইউ getopt" শব্দটি সাধারণত ব্যবহৃত হয় (যেমন ফ্রিবিএসডি তে))


3
এটি খুব সহায়ক ছিল, বিকল্পগুলি চেক করার জন্য getopt ব্যবহার করার ধারণা এবং তারপরে খুব সাধারণ লুপে এই বিকল্পগুলি প্রক্রিয়া করার সময় যখন আমি ব্যাশ স্ক্রিপ্টে দীর্ঘ শৈলীর বিকল্পগুলি যুক্ত করতে চাইতাম তখন তা খুব ভাল কাজ করে। ধন্যবাদ।
ianmjones

2
getoptলিনাক্স হয় না একটি গনুহ ইউটিলিটি এবং ঐতিহ্যগত getoptবাসদ থেকে AT & T ইউনিক্স থেকে প্রাথমিকভাবে আসে না। ksh93 এর getopts(এটিএন্ডটি থেকেও) জিএনইউ-স্টাইলের দীর্ঘ বিকল্পগুলি সমর্থন করে।
স্টিফেন চেজেলাস

@ স্টাফেনচাজেলাস - আপনার মন্তব্যগুলি প্রতিবিম্বিত করতে সম্পাদিত। আমি এখনও "জিএনইউ গেওপ্ট" শব্দটি পছন্দ করি যদিও এটি একটি মিসনোমারের কথা বলা হয়, কারণ এই সংস্করণটি জিএনইউ কনভেনশন অনুসরণ করে এবং সাধারণত একটি জিএনইউ প্রোগ্রামের মতো কাজ করে (যেমন ব্যবহার করা POSIXLY_CORRECT), যখন "লিনাক্স-বর্ধিত গেওপ্ট" ভুলভাবে পরামর্শ দেয় যে এই সংস্করণটি কেবলমাত্র উপস্থিত রয়েছে লিনাক্স।
আরবান ওয়াগাবন্ড

1
এটি ইউটি-লিনাক্স প্যাকেজ থেকে এসেছে, সুতরাং এটি লিনাক্স কেবল যেমন লিনাক্সের জন্য সফ্টওয়্যারগুলির বান্ডিল বোঝানো হয় (এটি getoptসহজেই অন্যান্য ইউনিটগুলিতে পোর্ট করা যেতে পারে তবে অন্যান্য সফ্টওয়্যারগুলি util-linuxলিনাক্স-নির্দিষ্ট are GNU getopt (3) ব্যবহার করে সমস্ত নন-জিএনইউ প্রোগ্রাম বুঝতে পারে $POSIX_CORRECT। উদাহরণস্বরূপ, আপনি বলবেন না যে aplayএটি কেবলমাত্র সেই কারণেই জিএনইউ। আমার সন্দেহ হয় যে ফ্রিবিএসডি যখন জিএনইউ গিওপ্টের উল্লেখ করে, তখন তাদের জিএনইউ গেটপট (3) সি এপিআই বোঝায়।
স্টিফেন চেজেলাস

@ স্টাফেইনচাজলাস - ফ্রিবিএসডি-র একটি ত্রুটি বার্তা রয়েছে "নির্ভরতা বাড়ান: দয়া করে জিএনইউ গিওপ্ট ইনস্টল করুন" যা নির্বিঘ্নে ব্যবহারটিকে গিওপট getopt(3) নয় বলে উল্লেখ করে ।
আরবান ওয়াগাবন্ড

202

বাশ্ট বিল্টিন গিওপটস ফাংশনটি ড্যাশ চরিত্রটি রেখে অপ্টস্পেকে একটি কোলন অনুসরণ করে দীর্ঘ বিকল্পগুলি পার্স করতে ব্যবহৃত হতে পারে:

#!/usr/bin/env bash 
optspec=":hv-:"
while getopts "$optspec" optchar; do
    case "${optchar}" in
        -)
            case "${OPTARG}" in
                loglevel)
                    val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
                    echo "Parsing option: '--${OPTARG}', value: '${val}'" >&2;
                    ;;
                loglevel=*)
                    val=${OPTARG#*=}
                    opt=${OPTARG%=$val}
                    echo "Parsing option: '--${opt}', value: '${val}'" >&2
                    ;;
                *)
                    if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
                        echo "Unknown option --${OPTARG}" >&2
                    fi
                    ;;
            esac;;
        h)
            echo "usage: $0 [-v] [--loglevel[=]<value>]" >&2
            exit 2
            ;;
        v)
            echo "Parsing option: '-${optchar}'" >&2
            ;;
        *)
            if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
                echo "Non-option argument: '-${OPTARG}'" >&2
            fi
            ;;
    esac
done

এক্সিকিউটেবল ফাইল নাম অনুলিপি = পর getopts_test.shসাম্প্রতিক কাজ করা , এক মত আউটপুট তৈরী করতে পারে

$ ./getopts_test.sh
$ ./getopts_test.sh -f
Non-option argument: '-f'
$ ./getopts_test.sh -h
usage: code/getopts_test.sh [-v] [--loglevel[=]<value>]
$ ./getopts_test.sh --help
$ ./getopts_test.sh -v
Parsing option: '-v'
$ ./getopts_test.sh --very-bad
$ ./getopts_test.sh --loglevel
Parsing option: '--loglevel', value: ''
$ ./getopts_test.sh --loglevel 11
Parsing option: '--loglevel', value: '11'
$ ./getopts_test.sh --loglevel=11
Parsing option: '--loglevel', value: '11'

স্পষ্টতই getopts OPTERRদীর্ঘ বিকল্পগুলির জন্য চেকিং বা বিকল্প-যুক্তি পার্সিং করে না forms উপরের স্ক্রিপ্টের খণ্ডটি দেখায় যে এটি কীভাবে ম্যানুয়ালি করা যায়। মূল নীতিটি দেবিয়ান অ্যালকুইস্ট শেল ("ড্যাশ") এও কাজ করে। বিশেষ ক্ষেত্রে দ্রষ্টব্য:

getopts -- "-:"  ## without the option terminator "-- " bash complains about "-:"
getopts "-:"     ## this works in the Debian Almquist shell ("dash")

মনে রাখবেন যে, গ্রেইগেটিক্স যেমন http://mywiki.wooledge.org/BashFAQ এ দেখায় , এই কৌশলটি শেলের একটি মানহীন আচরণকে ব্যবহার করে যা বিকল্প-যুক্তি (যেমন "-f ফাইলের নাম" এ ফাইলের নাম) অনুমতি দেয় বিকল্পটিতে সংবিধানিত হতে হবে ("ফাইল-নাম হিসাবে")। POSIX মান বলছেন তাদের মধ্যে একটি স্থান, যা ক্ষেত্রে হতে হবে "- longoption" বিকল্পটি-পার্স বিনষ্ট এবং অ বিকল্প আর্গুমেন্ট সব longoptions আবর্তিত হবে।


2
একটি প্রশ্ন: কি শব্দার্থবিদ্যা হয় !মধ্যে val="${!OPTIND}?
টমরোচে

2
@ টমরোচ এটি পরোক্ষ প্রতিস্থাপন: unix.stackexchange.com/a/41293/84316
ইকব্রোডি

2
@ সেব্রোডি: এটি কারণ যে দুটি যুক্তি আসলে প্রক্রিয়া করা হয়েছে, কেবল একটির বিপরীতে। প্রথম আর্গুমেন্ট শব্দ "loglevel", এবং পরবর্তী যুক্তি যে যুক্তি। এদিকে, getoptsস্বয়ংক্রিয়ভাবে কেবলমাত্র OPTIND1 দিয়ে ইনক্রিমেন্ট বৃদ্ধি পাচ্ছে , তবে আমাদের ক্ষেত্রে এটি 2 দ্বারা বাড়ানো দরকার, সুতরাং আমরা এটি 1 টি ম্যানুয়ালি getoptsবাড়িয়ে দেব, তারপরে এটি আমাদের কাছে স্বয়ংক্রিয়ভাবে আবার 1 দ্বারা বাড়িয়ে দেওয়া হোক।
ভিক্টর জামমানিয়ান

3
যেহেতু আমরা এখানে বাশ ভারসাম্য নিয়ে চলেছি: গাণিতিক এক্সপ্রেশনগুলির ভিতরে নগ্ন ভেরিয়েবলের নাম অনুমোদিত হয়, $প্রয়োজন নেই। OPTIND=$(( $OPTIND + 1 ))ন্যায়সঙ্গত হতে পারে OPTIND=$(( OPTIND + 1 ))। আরও মজার বিষয় হল, আপনি একটি গাণিতিক ভাবের ভিতরে ভেরিয়েবলগুলি বরাদ্দ করতে বা বাড়িয়ে দিতে পারেন, সুতরাং এটির আরও সংক্ষেপণ দেওয়া : $(( ++OPTIND ))বা সবসময় ইতিবাচক হবে (( ++OPTIND ))এমন অ্যাকাউন্টে ++OPTINDনেওয়াও সম্ভব, সুতরাং এটি -eবিকল্পটি দিয়ে কোনও শেল রান আপ করবে না । :-) gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html
ক্লেক

3
কেন --very-badসতর্কতা দেয় না ?
টম হেল

148

অন্তর্নির্মিত getoptsকমান্ডটি এখনও, আফাইক, কেবলমাত্র একক-অক্ষর বিকল্পগুলির মধ্যে সীমাবদ্ধ।

একটি বাহ্যিক প্রোগ্রাম রয়েছে (বা ব্যবহৃত হতে পারে) এমন একটি getoptবিকল্পের সেটকে পুনর্গঠিত করবে যেগুলি পার্স করা আরও সহজ। দীর্ঘ বিকল্পগুলিও পরিচালনা করতে আপনি সেই নকশাকে মানিয়ে নিতে পারেন। ব্যবহারের উদাহরণ:

aflag=no
bflag=no
flist=""
set -- $(getopt abf: "$@")
while [ $# -gt 0 ]
do
    case "$1" in
    (-a) aflag=yes;;
    (-b) bflag=yes;;
    (-f) flist="$flist $2"; shift;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*)  break;;
    esac
    shift
done

# Process remaining non-option arguments
...

আপনি getoptlongকমান্ড সহ একই স্কিম ব্যবহার করতে পারেন ।

মনে রাখবেন যে বাহ্যিক getoptপ্রোগ্রামের সাথে মৌলিক দুর্বলতা হ'ল তাদের স্পেসগুলির সাথে যুক্তিগুলি পরিচালনা করা এবং সেই স্পেসগুলি নির্ভুলভাবে সংরক্ষণে অসুবিধা। এ কারণেই বিল্ট-ইন getoptsউচ্চতর, যদিও এটি কেবলমাত্র একক-বর্ণের বিকল্পগুলি পরিচালনা করে limited


11
GNU সংস্করণ ব্যতীত getopt (যার আলাদা কলিং কনভেনশন রয়েছে) মূলত ভেঙে গেছে। এটা ব্যবহার করোনা. পরিবর্তে ** getopts
হেনড্রি

9
@ হ্যান্ড্রি - আপনার নিজস্ব লিঙ্ক থেকে: "নোট করুন যে গিওপগুলি জিএনইউ-স্টাইলের দীর্ঘ বিকল্পগুলি (- মায়োপশন) বা এক্সএফ 86-স্টাইলের দীর্ঘ বিকল্পগুলি (-মোশন) পার্স করতে সক্ষম নয়!"
টম অগার

1
জোনাথন - আপনার eval setউদ্ধৃতি সহ ব্যবহারের জন্য উদাহরণটি পুনরায় লিখতে হবে (নীচে আমার উত্তরটি দেখুন) যাতে এটি GNU getopt (লিনাক্সে ডিফল্ট) এর সাথেও সঠিকভাবে কাজ করে এবং স্পেসগুলি সঠিকভাবে পরিচালনা করে।
নগর ওয়াগাবন্ড

@ আরবানবাগাবন্ড: আমার কেন এমন করা উচিত তা আমি নিশ্চিত নই। প্রশ্নটি লিনাক্স নয়, ইউনিক্সকে ট্যাগ করা হয়েছে। আমি traditionalতিহ্যগতভাবে mechanismতিহ্যবাহী ব্যবস্থাটি দেখিয়ে চলেছি, এবং এতে যুক্তিগুলিতে ফাঁকা থাকা ইত্যাদি রয়েছে you আপনি যদি চান তবে আপনি আধুনিক লিনাক্স-নির্দিষ্ট সংস্করণটি প্রদর্শন করতে পারেন, এবং আপনার উত্তরটি তা করে। (আমি মনে করি, পাসিম, আপনার ${1+"$@"}আধুনিক ব্যবহারের শেলগুলির সাথে বিশেষত এবং লিনাক্সে যে কোনও শেল পাওয়া যায় তার সাথে মতবিরোধ রয়েছে a 1 / + "+ @"} ইন / বিন / শ ব্যবহার করে দেখুন সেই স্বরলিখনের আলোচনা))
জোনাথন লেফলার

আপনার এটি করা উচিত কারণ eval setজিএনইউ এবং বিএসডি উভয়ের সাথেই সঠিক কাজ করে getopt, তবে সরল setকেবল BSD এর সাথে সঠিক কাজ করে getopt। সুতরাং আপনি eval setএটি করার অভ্যাস পেতে লোকদের উত্সাহিত করার জন্যও ব্যবহার করতে পারেন । বিটিডব্লিউ ধন্যবাদ, আমি বুঝতে পারি না যে এর ${1+"$@"}আর দরকার নেই। আমাকে ম্যাক ওএস এক্স এবং লিনাক্স উভয় ক্ষেত্রেই কাজ করতে লিখতে হবে - দুজনের মধ্যে তারা প্রচুর বহনযোগ্যতা জোর করে। আমি শুধু চেক করা এবং "$@"প্রকৃতপক্ষে সব ডান জিনিস কাজ করে sh, bash, ksh, এবং zshMac OS X এর অধীনে; অবশ্যই লিনাক্স অধীনে।
নগর ওয়াগাবন্ড

78

এখানে একটি উদাহরণ যা প্রকৃতপক্ষে দীর্ঘ বিকল্পগুলির সাহায্যে ব্যবহার করে:

aflag=no
bflag=no
cargument=none

# options may be followed by one colon to indicate they have a required argument
if ! options=$(getopt -o abc: -l along,blong,clong: -- "$@")
then
    # something went wrong, getopt will put out an error message for us
    exit 1
fi

set -- $options

while [ $# -gt 0 ]
do
    case $1 in
    -a|--along) aflag="yes" ;;
    -b|--blong) bflag="yes" ;;
    # for options with required arguments, an additional shift is required
    -c|--clong) cargument="$2" ; shift;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*) break;;
    esac
    shift
done

1
আপনার eval setউদ্ধৃতি সহ ব্যবহারের জন্য উদাহরণটি পুনরায় লিখতে হবে (নীচে আমার উত্তর দেখুন) যাতে এটি GNU getopt (লিনাক্সে ডিফল্ট) এর সাথেও সঠিকভাবে কাজ করে এবং স্পেসগুলি সঠিকভাবে পরিচালনা করে।
নগর ওয়াগাবন্ড

1
যদিও getoptপ্রশ্নটি getoptsযদিও এটির ক্ষেত্রে রয়েছে ।
নিক্লাস বার্গ্লুন্ড

হয় (--, (-*এবং (*বৈধ নিদর্শন? তারা কীভাবে থেকে ভিন্ন --, -*এবং *?
মাওলান

@ মাওলান - শীর্ষস্থানীয় উন্মুক্ত প্রথম বন্ধনী alচ্ছিক, সুতরাং একটি স্তরের সাথে (--)মিল রয়েছে । এই optionচ্ছিক নেতৃস্থানীয় পেরেনগুলির অসম ইন্ডেন্টেশন এবং অসামঞ্জস্যপূর্ণ ব্যবহারটি দেখতে অদ্ভুত, তবে উত্তরটির বর্তমান কোডটি আমার কাছে বৈধ বলে মনে হচ্ছে। --)case
অ্যাডাম কাটজ

59

দীর্ঘতর বিকল্পগুলি স্ট্যান্ডার্ড getoptsবিল্টইন দ্বারা "আর্গুমেন্ট" হিসাবে -"বিকল্প" হিসাবে পার্স করা যায়

এটি পোর্টেবল এবং নেটিভ পসিক্স শেল - কোনও বাহ্যিক প্রোগ্রাম বা বাশিজমের দরকার নেই।

আর্গুমেন্ট হিসাবে এই সহায়িকার কার্যকরী দীর্ঘ অপশন -বিকল্প, তাই --alphaবলে মনে করা হয় getoptsযেমন -যুক্তি দিয়ে alphaএবং --bravo=fooহিসেবে দেখা হয় -আর্গুমেন্ট সহ bravo=foo। সত্য যুক্তি সহজ প্রতিস্থাপন সঙ্গে চাষ করা যেতে পারে: ${OPTARG#*=}

এই উদাহরণে -bএবং -c(এবং তাদের দীর্ঘ ফর্মগুলি --bravoএবং --charlie) এর বাধ্যতামূলক যুক্তি রয়েছে। দীর্ঘ বিকল্পগুলির পক্ষে যুক্তিগুলি সমান চিহ্নগুলির পরে আসে, উদাহরণস্বরূপ --bravo=foo(দীর্ঘ বিকল্পগুলির জন্য স্পেস ডিলিমিটারগুলি কার্যকর করা কঠিন হবে, নীচে দেখুন)।

যেহেতু এটি getoptsঅন্তর্নির্মিত ব্যবহার করে , এই দ্রবণটি ব্যবহারের মতো সমর্থন করে cmd --bravo=foo -ac FILE(যা বিকল্প বিকল্পগুলির সাথে সম্মিলিত বিকল্প -aএবং -cদীর্ঘতর বিকল্পগুলি ইন্টারলেভ করে) যখন অন্য বেশিরভাগ উত্তর এখানে হয় লড়াই করে বা এটি করতে ব্যর্থ হয়।

die() { echo "$*" >&2; exit 2; }  # complain to STDERR and exit with error
needs_arg() { if [ -z "$OPTARG" ]; then die "No arg for --$OPT option"; fi; }

while getopts ab:c:-: OPT; do
  # support long options: https://stackoverflow.com/a/28466267/519360
  if [ "$OPT" = "-" ]; then   # long option: reformulate OPT and OPTARG
    OPT="${OPTARG%%=*}"       # extract long option name
    OPTARG="${OPTARG#$OPT}"   # extract long option argument (may be empty)
    OPTARG="${OPTARG#=}"      # if long option argument, remove assigning `=`
  fi
  case "$OPT" in
    a | alpha )    alpha=true ;;
    b | bravo )    needs_arg; bravo="$OPTARG" ;;
    c | charlie )  needs_arg; charlie="$OPTARG" ;;
    ??* )          die "Illegal option --$OPT" ;;  # bad long option
    \? )           exit 2 ;;  # bad short option (error reported via getopts)
  esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list

যখন বিকল্পটি ড্যাশ ( -) হয়, এটি একটি দীর্ঘ বিকল্প। getoptsপ্রকৃত দীর্ঘ বিকল্পটি এখানে বিশ্লেষণ করবে $OPTARG, যেমন --bravo=fooমূলত সেট করে OPT='-'এবং OPTARG='bravo=foo'। প্রথম সমান চিহ্ন ( আমাদের উদাহরণে) এর আগে এই পদক্ষেপটি এর ifসামগ্রীতে সেট $OPTহয়ে যায় এবং তারপরে এটি সরিয়ে দেয় ( এই পদক্ষেপে ফলন দেওয়া , বা কোনও খালি স্ট্রিং না থাকলে )। অবশেষে, আমরা যুক্তির নেতৃস্থানীয় কেটে ফেলি । এই মুহুর্তে, হয় একটি সংক্ষিপ্ত বিকল্প (একটি অক্ষর) বা একটি দীর্ঘ বিকল্প (2+ অক্ষর)।$OPTARGbravo$OPTARG=foo==$OPT

caseতারপর পারেন স্বল্প বা দীর্ঘ অপশন মেলে। সংক্ষিপ্ত বিকল্পগুলির জন্য, getoptsস্বয়ংক্রিয়ভাবে বিকল্পগুলি এবং নিখোঁজ যুক্তিগুলির সম্পর্কে অভিযোগ করে, সুতরাং আমাদের needs_argফাংশনটি ব্যবহার করে ম্যানুয়ালি সেইগুলি প্রতিলিপি করতে হবে, যা $OPTARGখালি থাকলে প্রাণঘাতী থেকে বেরিয়ে আসে । ??*শর্ত কোনো অবশিষ্ট দীর্ঘ বিকল্প (ম্যাচ হবে ?একটি অক্ষর মিলে যায় এবং *ম্যাচ শূন্য বা তার বেশি, তাই ??*2+ অক্ষরের সাথে মেলে), আমাদের প্রস্থান করার পূর্বে "অবৈধ বিকল্প" ত্রুটি জারি করার অনুমতি দেয়।

(অল-আপারকেসেস ভেরিয়েবলের নাম সম্পর্কে একটি নোট: সাধারণত, পরামর্শটি হ'ল সিস্টেম ব্যবহারের জন্য অল-আপারকেস ভেরিয়েবলগুলি সংরক্ষণ করার জন্য I'm আমি $OPTএটির সাথে তাল মিলিয়ে রাখতে সর্ব-বড় হাতের মতো রাখছি $OPTARG, তবে এটি সেই কনভেনশনটি ভেঙে ফেলেছে I আমি এটি মনে করি ফিট করে কারণ এটি এমন কিছু যা করা উচিত সিস্টেমটি করা উচিত ছিল এবং এটি নিরাপদ হওয়া উচিত কারণ এমন কোনও মান (আফাইক) নেই যা এ জাতীয় পরিবর্তনশীল ব্যবহার করে))


দীর্ঘ অপশনগুলিতে অপ্রত্যাশিত যুক্তি সম্পর্কে অভিযোগ জানাতে, বাধ্যতামূলক যুক্তিগুলির জন্য আমরা যা করেছি তা নকল করুন: একটি সহায়ক ফাংশন ব্যবহার করুন। যখন কোনও প্রত্যাশিত হয় না তখন একটি যুক্তি সম্পর্কে অভিযোগ করার জন্য পরীক্ষাটি প্রায় কাছাকাছি ফ্লিপ করুন:

no_arg() { if [ -n "$OPTARG" ]; then die "No arg allowed for --$OPT option"; fi; }

এই উত্তরের একটি পুরানো সংস্করণে স্থান-বিস্মৃত যুক্তিগুলির সাথে দীর্ঘ বিকল্পগুলি গ্রহণ করার চেষ্টা ছিল, তবে এটি নির্ভরযোগ্য ছিল না; getoptsযুক্তিটি তার ক্ষেত্রের বাইরে ছিল এবং ম্যানুয়ালি ইনক্রিমেন্টিং $OPTINDসমস্ত শেলগুলিতে কাজ করে না এই ধারণাটি অকাল থেকেই শেষ হতে পারে ।

এটি এর মধ্যে একটি কৌশল ব্যবহার করে সম্পন্ন হবে:

এবং তারপরে এমন কিছু দিয়ে শেষ হয়েছিল [ $# -gt $OPTIND ] && OPTIND=$((OPTIND+1))


খুব সুন্দর স্বয়ংসম্পূর্ণ সমাধান। একটি প্রশ্ন: যেহেতু letter-cকোনও যুক্তির প্রয়োজন নেই, তাই এটি কি যথেষ্ট পরিমাণে ব্যবহার করা উচিত নয় letter-c)?; *অপ্রয়োজনীয় বলে মনে হয়।
ফিলিপ কেয়ার্নস

1
@ আর্ন অবস্থানগত যুক্তিগুলি খারাপ ইউএক্স; এগুলি বোঝা শক্ত এবং alচ্ছিক যুক্তিগুলি বেশ অগোছালো। getoptsএটি প্রথম অবস্থানগত যুক্তিতে থামায় কারণ এটি তাদের সাথে ডিল করার জন্য ডিজাইন করা হয়নি। এই তাদের নিজস্ব আর্গুমেন্ট, যেমন সঙ্গে উপ-কমান্ড পারবেন git diff --color, তাই আমি ব্যাখ্যা চাই command --foo=moo bar --baz wazতার হিসাবে --fooএকটি আর্গুমেন্ট হিসাবে commandএবং --baz wazএকটি যুক্তি (বিকল্প) হিসেবে barসাব-কমান্ড। উপরের কোড দিয়ে এটি করা যেতে পারে। আমি প্রত্যাখ্যান করি --bravo -blahকারণ --bravoএকটি যুক্তি প্রয়োজন এবং এটি অস্পষ্ট যে -blahএটি অন্য বিকল্প নয়।
অ্যাডাম কাটজ

1
আমি ইউএক্স সম্পর্কে একমত নই: আপনি যতক্ষণ না তাদের সংখ্যা সীমাবদ্ধ করেন ততক্ষণ অবস্থানগত যুক্তিগুলি কার্যকর এবং সহজ, (সর্বাধিক 2 বা 1 প্লাস এন-অফ-দ্য একই ধরণের)। কীওয়ার্ড আর্গুমেন্টগুলির সাথে তাদের ছেদ করা সম্ভব হওয়া উচিত, কারণ ব্যবহারকারীরা তখন কমান্ড ধাপে ধাপে (যেমন ls abc -la) তৈরি করতে পারেন।
আর্নে বাবেনহাউসারহিডে

1
@ অ্যাডামক্যাটজ: আমি এটি দিয়ে একটি ছোট্ট নিবন্ধ লিখেছি: draketo.de/english/free-software/ Shell - argument - parsing - পিছনের বিকল্পগুলি ধরার জন্য বাকী যুক্তিগুলির বারবার পড়াও অন্তর্ভুক্ত।
আর্নি Babenhauserheide

1
@ আর্নেবাবেনহাউজারিহাইড: স্পেস-সীমাবদ্ধ যুক্তি সমর্থন করার জন্য আমি এই উত্তরটি আপডেট করেছি। এটি evalপসিক্স শেলের মধ্যে প্রয়োজন হওয়ায় এটি বাকি উত্তরের নীচে তালিকাভুক্ত।
অ্যাডাম কাটজ

33

কটাক্ষপাত shFlags (: SH, ব্যাশ, ড্যাশ, ksh, লিনাক্স, সোলারিস, ইত্যাদি উপর zsh অর্থ) যা পোর্টেবল শেল লাইব্রেরী।

এটি আপনার স্ক্রিপ্টে একটি লাইন যুক্ত করার মতো নতুন পতাকা যুক্ত করা সহজ করে তোলে এবং এটি একটি স্বয়ংক্রিয় উত্পন্ন উত্সাহিত কার্য ক্রিয়া সরবরাহ করে।

এখানে shFlagHello, world! ব্যবহার করে একটি সহজ :

#!/bin/sh

# source shflags from current directory
. ./shflags

# define a 'name' command-line string flag
DEFINE_string 'name' 'world' 'name to say hello to' 'n'

# parse the command-line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

# say hello
echo "Hello, ${FLAGS_name}!"

দীর্ঘতর বিকল্পগুলি (যেমন লিনাক্স) সমর্থন করে এমন ওএসগুলির উন্নত রপ্তানি রয়েছে যা আপনি করতে পারেন:

$ ./hello_world.sh --name Kate
Hello, Kate!

বিশ্রামের জন্য, আপনাকে অবশ্যই সংক্ষিপ্ত বিকল্পটি ব্যবহার করতে হবে:

$ ./hello_world.sh -n Kate
Hello, Kate!

একটি নতুন পতাকা যুক্ত করা একটি নতুন যুক্ত করার মতোই সহজ DEFINE_ call


2
এটি চমত্কার হলেও দুর্ভাগ্যক্রমে আমার getopt (OS X) আর্গুমেন্টে ফাঁকা জায়গা সমর্থন করে না: / বিকল্প আছে কিনা তা অবাক করে দিয়েছি।
অ্যালাস্টার স্টুয়ার্ট

@ অ্যাস্টায়ারস্টুয়ার্ট - ওএস এক্সে আসলেই বিকল্প রয়েছে G
নগর ওয়াগাবন্ড

3
@ উরবানভেগাবন্ড - নন সিস্টেম ডিফল্ট সরঞ্জাম ইনস্টলেশন দুর্ভাগ্যক্রমে যথেষ্ট পোর্টেবল সরঞ্জামের জন্য একটি গ্রহণযোগ্য প্রয়োজনীয়তা নয়।
অ্যালাস্টার স্টুয়ার্ট

@ অ্যাস্টায়ারস্টুয়ার্ট - পোর্টেবল সমাধানের জন্য আমার উত্তরটি দেখুন যা GNU getopt এর চেয়ে getopts বিল্টিন ব্যবহার করে। এটি বেসিক getopts ব্যবহারের মতো তবে দীর্ঘ বিকল্পগুলির জন্য অতিরিক্ত পুনরাবৃত্তি সহ।
অ্যাডাম কাটজ

31

getoptsসংক্ষিপ্ত / দীর্ঘ বিকল্প এবং যুক্তি সহ ব্যবহার করে Using


সমস্ত সংমিশ্রণের সাথে কাজ করে, যেমন:

  • foobar -f - বার
  • foobar --foo -b
  • foobar -bf --bar --foobar
  • foobar -fbFBAshorty --bar -FB --arguments = লংহর্ন
  • foobar -fA "পাঠ্য সংক্ষিপ্ত" -বি --আরগমেন্টস = "পাঠ্য দীর্ঘজীবী"
  • bash foobar -F --barfoo
  • sh foobar -B --foobar - ...
  • bash ./foobar -F --bar

এই উদাহরণের জন্য কিছু ঘোষণা

Options=$@
Optnum=$#
sfoo='no '
sbar='no '
sfoobar='no '
sbarfoo='no '
sarguments='no '
sARG=empty
lfoo='no '
lbar='no '
lfoobar='no '
lbarfoo='no '
larguments='no '
lARG=empty

ব্যবহারের কার্যটি কীভাবে দেখায়

function _usage() 
{
  ###### U S A G E : Help and ERROR ######
  cat <<EOF
   foobar $Options
  $*
          Usage: foobar <[options]>
          Options:
                  -b   --bar            Set bar to yes    ($foo)
                  -f   --foo            Set foo to yes    ($bart)
                  -h   --help           Show this message
                  -A   --arguments=...  Set arguments to yes ($arguments) AND get ARGUMENT ($ARG)
                  -B   --barfoo         Set barfoo to yes ($barfoo)
                  -F   --foobar         Set foobar to yes ($foobar)
EOF
}

[ $# = 0 ] && _usage "  >>>>>>>> no options given "

getops দীর্ঘ / সংক্ষিপ্ত পতাকা পাশাপাশি দীর্ঘ আর্গুমেন্ট সহ

while getopts ':bfh-A:BF' OPTION ; do
  case "$OPTION" in
    b  ) sbar=yes                       ;;
    f  ) sfoo=yes                       ;;
    h  ) _usage                         ;;   
    A  ) sarguments=yes;sARG="$OPTARG"  ;;
    B  ) sbarfoo=yes                    ;;
    F  ) sfoobar=yes                    ;;
    -  ) [ $OPTIND -ge 1 ] && optind=$(expr $OPTIND - 1 ) || optind=$OPTIND
         eval OPTION="\$$optind"
         OPTARG=$(echo $OPTION | cut -d'=' -f2)
         OPTION=$(echo $OPTION | cut -d'=' -f1)
         case $OPTION in
             --foo       ) lfoo=yes                       ;;
             --bar       ) lbar=yes                       ;;
             --foobar    ) lfoobar=yes                    ;;
             --barfoo    ) lbarfoo=yes                    ;;
             --help      ) _usage                         ;;
             --arguments ) larguments=yes;lARG="$OPTARG"  ;; 
             * )  _usage " Long: >>>>>>>> invalid options (long) " ;;
         esac
       OPTIND=1
       shift
      ;;
    ? )  _usage "Short: >>>>>>>> invalid options (short) "  ;;
  esac
done

আউটপুট

##################################################################
echo "----------------------------------------------------------"
echo "RESULT short-foo      : $sfoo                                    long-foo      : $lfoo"
echo "RESULT short-bar      : $sbar                                    long-bar      : $lbar"
echo "RESULT short-foobar   : $sfoobar                                 long-foobar   : $lfoobar"
echo "RESULT short-barfoo   : $sbarfoo                                 long-barfoo   : $lbarfoo"
echo "RESULT short-arguments: $sarguments  with Argument = \"$sARG\"   long-arguments: $larguments and $lARG"

উপরেরটি একটি সমন্বিত স্ক্রিপ্টে সংযুক্ত করা

#!/bin/bash
# foobar: getopts with short and long options AND arguments

function _cleanup ()
{
  unset -f _usage _cleanup ; return 0
}

## Clear out nested functions on exit
trap _cleanup INT EXIT RETURN

###### some declarations for this example ######
Options=$@
Optnum=$#
sfoo='no '
sbar='no '
sfoobar='no '
sbarfoo='no '
sarguments='no '
sARG=empty
lfoo='no '
lbar='no '
lfoobar='no '
lbarfoo='no '
larguments='no '
lARG=empty

function _usage() 
{
  ###### U S A G E : Help and ERROR ######
  cat <<EOF
   foobar $Options
   $*
          Usage: foobar <[options]>
          Options:
                  -b   --bar            Set bar to yes    ($foo)
                    -f   --foo            Set foo to yes    ($bart)
                      -h   --help           Show this message
                  -A   --arguments=...  Set arguments to yes ($arguments) AND get ARGUMENT ($ARG)
                  -B   --barfoo         Set barfoo to yes ($barfoo)
                  -F   --foobar         Set foobar to yes ($foobar)
EOF
}

[ $# = 0 ] && _usage "  >>>>>>>> no options given "

##################################################################    
#######  "getopts" with: short options  AND  long options  #######
#######            AND  short/long arguments               #######
while getopts ':bfh-A:BF' OPTION ; do
  case "$OPTION" in
    b  ) sbar=yes                       ;;
    f  ) sfoo=yes                       ;;
    h  ) _usage                         ;;   
    A  ) sarguments=yes;sARG="$OPTARG"  ;;
    B  ) sbarfoo=yes                    ;;
    F  ) sfoobar=yes                    ;;
    -  ) [ $OPTIND -ge 1 ] && optind=$(expr $OPTIND - 1 ) || optind=$OPTIND
         eval OPTION="\$$optind"
         OPTARG=$(echo $OPTION | cut -d'=' -f2)
         OPTION=$(echo $OPTION | cut -d'=' -f1)
         case $OPTION in
             --foo       ) lfoo=yes                       ;;
             --bar       ) lbar=yes                       ;;
             --foobar    ) lfoobar=yes                    ;;
             --barfoo    ) lbarfoo=yes                    ;;
             --help      ) _usage                         ;;
               --arguments ) larguments=yes;lARG="$OPTARG"  ;; 
             * )  _usage " Long: >>>>>>>> invalid options (long) " ;;
         esac
       OPTIND=1
       shift
      ;;
    ? )  _usage "Short: >>>>>>>> invalid options (short) "  ;;
  esac
done

এটি একাধিক দীর্ঘ আর্গুমেন্ট (-) দিয়ে কাজ করে না। মনে হয় এটি আমার জন্য প্রথমটি পড়বে।
সিনেমাস্টিক

@ সিনেস্টেথিক - হ্যাঁ, আমি evalদীর্ঘ বিকল্পগুলির সাথে ব্যবধানযুক্ত যুক্তিগুলির পদ্ধতির সাথে খেলছিলাম এবং এটি নির্দিষ্ট শাঁসের সাথে এটি অবিশ্বাস্যরূপে পেয়েছি (যদিও আমি আশা করি এটি ব্যাশের সাথে কাজ করবে, এই ক্ষেত্রে আপনাকে ব্যবহার করতে হবে না eval)। কীভাবে দীর্ঘ বিকল্পের যুক্তিগুলি গ্রহণ করতে হয় এবং স্থান ব্যবহারের জন্য আমার উল্লিখিত প্রয়াসের জন্য আমার উত্তর দেখুন =। এই সমাধানটি cutকয়েকবার ব্যবহার করার সময় আমার সমাধানটি বাহ্যিক কলগুলি করে না ।
অ্যাডাম কাটজ

24

অন্য উপায়...

# translate long options to short
for arg
do
    delim=""
    case "$arg" in
       --help) args="${args}-h ";;
       --verbose) args="${args}-v ";;
       --config) args="${args}-c ";;
       # pass through anything else
       *) [[ "${arg:0:1}" == "-" ]] || delim="\""
           args="${args}${delim}${arg}${delim} ";;
    esac
done
# reset the translated args
eval set -- $args
# now we can process with getopt
while getopts ":hvc:" opt; do
    case $opt in
        h)  usage ;;
        v)  VERBOSE=true ;;
        c)  source $OPTARG ;;
        \?) usage ;;
        :)
        echo "option -$OPTARG requires an argument"
        usage
        ;;
    esac
done

1
এর জন্য কি প্রতিটি $argsপুনর্নির্ধারণের জন্য জায়গার দরকার নেই ? এটি এমনকি আউট বাশিজমেও করা যেতে পারে তবে এই কোডটি বিকল্প এবং যুক্তিগুলির ফাঁকা স্থান হারাবে (আমি মনে করি না $delimকৌশলটি কাজ করবে)। পরিবর্তে আপনি ভিতরে চালাতে পারেনset for লুপ আপনার যদি যথেষ্ট সতর্কতা অবলম্বন শুধুমাত্র প্রথম পুনরাবৃত্তির তে এটি খালি করতে হয়। বাশিজম ছাড়াই এখানে একটি নিরাপদ সংস্করণ
অ্যাডাম কাটজ

18

আমি এইভাবে সমাধান করেছি:

# A string with command options
options=$@

# An array with all the arguments
arguments=($options)

# Loop index
index=0

for argument in $options
  do
    # Incrementing index
    index=`expr $index + 1`

    # The conditions
    case $argument in
      -a) echo "key $argument value ${arguments[index]}" ;;
      -abc) echo "key $argument value ${arguments[index]}" ;;
    esac
  done

exit;

আমি কি বোবা হয়ে যাচ্ছি নাকি কিছু? getoptএবং getoptsতাই বিভ্রান্তিকর।


1
এটি আমার পক্ষে কাজ করে বলে মনে হচ্ছে, এই পদ্ধতিতে সমস্যাটি কী তা আমি জানি না, তবে এটি সহজ বলে মনে হচ্ছে, সুতরাং অন্য প্রত্যেকে এটি ব্যবহার না করার কারণ অবশ্যই থাকতে হবে।
বিলি মুন

1
@ বিলি হ্যাঁ, এটি সহজ কারণ আমি আমার পরামিতিগুলি ইত্যাদি পরিচালনা করতে কোনও স্ক্রিপ্ট ব্যবহার করি না মূলত আমি আর্গুমেন্টের স্ট্রিং ($ @) কে একটি অ্যারে রূপান্তর করি এবং আমি এটির মধ্য দিয়ে লুপ করি। লুপে, বর্তমান মানটি মূল এবং পরবর্তীটির মান হবে। যে হিসাবে সহজ।

1
@ থিডোর আমি আনন্দিত এটি আপনার পক্ষে সহায়ক ছিল! এটি আমার জন্যও ব্যথা ছিল। আপনি যদি আগ্রহী হন তবে আপনি এখানে এর কার্যকারিতাটির

2
অবশ্যই আমি দেখেছি সবচেয়ে সহজ উপায়। আমি এটিকে কিছুটা পরিবর্তন করেছি যেমন এক্সপ্রেসের পরিবর্তে i = $ (($ i + 1)) ব্যবহার করি তবে ধারণাটি এয়ার-টাইট।
থমাস ডিগানান

6
আপনি মোটেও বোবা নন, তবে আপনি একটি বৈশিষ্ট্য অনুপস্থিত হতে পারেন: getopt (গুলি) মিশ্রিত বিকল্পগুলি সনাক্ত করতে পারে (যেমন: -ltrবা -lt -rপাশাপাশি -l -t -r)। এবং এটি কিছু ত্রুটি পরিচালনা পরিচালনা এবং বিকল্প চিকিত্সা শেষ হয়ে গেলে চিকিত্সা প্যারামিটারগুলি সরিয়ে নিয়ে যাওয়ার সহজ উপায় সরবরাহ করে।
অলিভিয়ার ডুলাক

14

আপনি যদি getoptনির্ভরতা না চান তবে আপনি এটি করতে পারেন:

while test $# -gt 0
do
  case $1 in

  # Normal option processing
    -h | --help)
      # usage and help
      ;;
    -v | --version)
      # version info
      ;;
  # ...

  # Special cases
    --)
      break
      ;;
    --*)
      # error unknown (long) option $1
      ;;
    -?)
      # error unknown (short) option $1
      ;;

  # FUN STUFF HERE:
  # Split apart combined short options
    -*)
      split=$1
      shift
      set -- $(echo "$split" | cut -c 2- | sed 's/./-& /g') "$@"
      continue
      ;;

  # Done with options
    *)
      break
      ;;
  esac

  # for testing purposes:
  echo "$1"

  shift
done

অবশ্যই, তারপরে আপনি একটি ড্যাশ দিয়ে দীর্ঘ স্টাইল বিকল্প ব্যবহার করতে পারবেন না। এবং যদি আপনি সংক্ষিপ্ত সংস্করণগুলি (যেমন --verbos এর পরিবর্তে --verbos) যুক্ত করতে চান, তবে আপনাকে সেগুলি ম্যানুয়ালি যুক্ত করতে হবে।

আপনি যদি getoptsদীর্ঘ বিকল্পগুলির সাথে কার্যকারিতা পেতে চাইছেন তবে এটি করার একটি সহজ উপায়।

আমি একটি এই স্নিপেট করা সারকথা


এটি কেবল একবারে একটি দীর্ঘ বিকল্পের সাথে কাজ করে বলে মনে হয়, তবে এটি আমার প্রয়োজনীয়তা পূরণ করেছে। ধন্যবাদ!
কিংজেফ্রে

বিশেষ ক্ষেত্রে --)মনে হয় shift ;নিখোঁজ রয়েছে। এই মুহুর্তে --প্রথম অ বিকল্প বিকল্প হিসাবে যুক্তি হিসাবে থাকবে।
dgw

আমি মনে করি যে এটি আসলে আরও ভাল উত্তর, যদিও ডিজিডব্লু হিসাবে পয়েন্টটি দেখায় --বিকল্পটির একটি প্রয়োজন shift। আমি বলতে এটা উত্তম, কারণ বিকল্প পারেন প্ল্যাটফর্ম নির্ভরশীল সংস্করণ getoptবা getopts_longঅথবা আপনি স্বল্প অপশন বলপূর্বক কমান্ড শুরুতে শুধুমাত্র ব্যবহার করা যেতে আছে (অর্থাত - আপনি ব্যবহার getoptsতারপর পরে দীর্ঘ অপশন প্রক্রিয়ার মধ্যে), যেহেতু এই কোনো আদেশ দেয় এবং সম্পূর্ণ নিয়ন্ত্রণ।
হারাভিক্ক

এই উত্তরটি আমাকে বিস্মিত করে তোলে যে আমাদের কাছে কাজটি করার জন্য কয়েক ডজন জবাবের থ্রেড রয়েছে যা এই একেবারে পরিষ্কার এবং সরল সমাধান ছাড়া আর কিছুই করা যায় না , এবং যদি বিলিয়ন জমিদারি (গুলি) প্রমাণিত করা ব্যতীত অন্য কোন মামলার ব্যবহারের কারণ থাকে তবে নিজেকে।
ফ্লোরিয়ান হিগল

11

অন্তর্নির্মিত এটি getoptsকরতে পারে না। একটি বহিরাগত গোটপট (1) প্রোগ্রাম রয়েছে যা এটি করতে পারে তবে আপনি এটি ইউটি-লিনাক্স প্যাকেজ থেকে লিনাক্সে পেতে পারেন । এটি একটি উদাহরণ স্ক্রিপ্ট getopt-parse.bash সহ আসে ।

এখানে একটা হল getopts_longএকটি শেল ফাংশন হিসাবে লিখিত।


3
getopt1993 সালে FreeBSD 'র সংস্করণ 1.0 মধ্যে অন্তর্ভুক্ত করা হয় এবং তারপর থেকে FreeBSD' র অংশ হয়েছে। এ হিসাবে, এটি অ্যাপল এর ডারউইন প্রকল্পের অন্তর্ভুক্তির জন্য ফ্রিবিএসডি ৪.x থেকে গৃহীত হয়েছিল। ওএস এক্স 10.6.8 হিসাবে, অ্যাপল অন্তর্ভুক্ত ম্যান পৃষ্ঠাটি ফ্রিবিএসডি ম্যান পৃষ্ঠাটির সঠিক নকল হিসাবে রয়ে গেছে। সুতরাং হ্যাঁ, এটি ওএস এক্স এবং লিনাক্সের পাশে অন্যান্য অপারেটিং সিস্টেমগুলির গবসের অন্তর্ভুক্ত। ভুল উত্তর দেওয়ার জন্য এই উত্তর -1।
ঘোটি

8
#!/bin/bash
while getopts "abc:d:" flag
do
  case $flag in
    a) echo "[getopts:$OPTIND]==> -$flag";;
    b) echo "[getopts:$OPTIND]==> -$flag";;
    c) echo "[getopts:$OPTIND]==> -$flag $OPTARG";;
    d) echo "[getopts:$OPTIND]==> -$flag $OPTARG";;
  esac
done

shift $((OPTIND-1))
echo "[otheropts]==> $@"

exit

#!/bin/bash
until [ -z "$1" ]; do
  case $1 in
    "--dlong")
      shift
      if [ "${1:1:0}" != "-" ]
      then
        echo "==> dlong $1"
        shift
      fi;;
    *) echo "==> other $1"; shift;;
  esac
done
exit

2
একটি ব্যাখ্যা ভাল হবে। প্রথম স্ক্রিপ্টটি সংক্ষিপ্ত বিকল্পগুলি কেবল তখনই গ্রহণ করে যখন দ্বিতীয় স্ক্রিপ্টটির দীর্ঘ বিকল্প আর্গুমেন্ট পার্সিংয়ে একটি বাগ থাকে; এর পরিবর্তনশীলটি "${1:0:1}"আর্গুমেন্ট # 1 এর জন্য হওয়া উচিত , সূচক 0, দৈর্ঘ্য 1 এ স্ট্রিং করা উচিত short
অ্যাডাম কাটজ

7

ইন ksh93, getoptsদীর্ঘ নাম সমর্থন করে ...

while getopts "f(file):s(server):" flag
do
    echo "$flag" $OPTIND $OPTARG
done

বা তাই আমি যে টিউটোরিয়ালগুলি পেয়েছি তা বলেছে। চেষ্টা করে দেখুন।


4
এটি ksh93 এর অন্তর্নির্মিত অন্তর্নির্মিত। এই বাক্য গঠনটি ছাড়াও এর আরও জটিল বাক্য গঠন রয়েছে যা সংক্ষিপ্ত সমতুল্য ছাড়া দীর্ঘ বিকল্পগুলিও মঞ্জুরি দেয় এবং আরও অনেক কিছু।
জিলিস

2
একটি যুক্তিসঙ্গত উত্তর। ওপি WHAT শেল নির্দিষ্ট করে নি।
ঘোটি

6

আমি এখন থেকে কেবল শেল স্ক্রিপ্টগুলি লিখি এবং অনুশীলনের বাইরে পড়ে যাই, তাই কোনও প্রতিক্রিয়া প্রশংসা করা হয়।

@ আরভিড অনুরোধের প্রস্তাবিত কৌশলটি ব্যবহার করে আমরা কিছু ব্যবহারকারীর ত্রুটি লক্ষ্য করেছি। যে ব্যবহারকারী কোনও মান অন্তর্ভুক্ত করতে ভুলে যায় দুর্ঘটনাক্রমে পরবর্তী বিকল্পের নামটি মান হিসাবে গণ্য হবে:

./getopts_test.sh --loglevel= --toc=TRUE

"লগলিভেল" এর মান "--toc = সত্য" হিসাবে দেখা দেবে। এটি এড়ানো যায়।

আমি ম্যানুয়াল পার্সিংয়ের http://mwiki.wooledge.org/BashFAQ/035 আলোচনা থেকে সিএলআইয়ের জন্য ব্যবহারকারীর ত্রুটি পরীক্ষা করার বিষয়ে কিছু ধারণা মানিয়েছি। আমি "-" এবং "-" উভয় যুক্তিই পরিচালনা করতে ত্রুটি প্রবেশ করিয়েছি।

তারপরে আমি সিনট্যাক্সটি নিয়ে চারদিকে ঝাঁকুনি শুরু করেছি, সুতরাং এখানে যে কোনও ত্রুটি রয়েছে তা কঠোরভাবে আমার দোষ, মূল লেখক নয়।

আমার পদ্ধতির সাহায্যকারীরা সমান চিহ্ন সহ বা ছাড়াই দীর্ঘ প্রবেশ করতে পছন্দ করে। অর্থাৎ এটির "--loglevel 9" "" -loglevel = 9 "হিসাবে একই প্রতিক্রিয়া থাকা উচিত। - / স্পেস পদ্ধতিতে, ব্যবহারকারী কোনও যুক্তি ভুলে গিয়েছে কিনা তা নিশ্চিত করে জানা সম্ভব নয়, তাই কিছু অনুমান করা দরকার।

  1. যদি ব্যবহারকারীর দীর্ঘ / সমান চিহ্ন বিন্যাস (--opt =) থাকে, তবে = পরে একটি স্থান একটি ত্রুটি ট্রিগার করে কারণ একটি যুক্তি সরবরাহ করা হয়নি।
  2. ব্যবহারকারীর দীর্ঘ / স্পেস আর্গুমেন্ট (--opt) থাকলে, কোনও আর্গুমেন্ট অনুসরণ না করলে (কমান্ডের সমাপ্তি) অথবা আর্গুমেন্ট ড্যাশ দিয়ে শুরু হলে এই স্ক্রিপ্টটি ব্যর্থ হয়)

আপনি যদি এটি শুরু করে থাকেন তবে "--opt = মান" এবং "--opt মান" ফর্ম্যাটগুলির মধ্যে একটি আকর্ষণীয় পার্থক্য রয়েছে। সমান চিহ্ন সহ, কমান্ড লাইন আর্গুমেন্টটিকে "opt = value" হিসাবে দেখা হয় এবং "=" এ পৃথক করার জন্য স্ট্রিংকে পার্সিং করা হ্যান্ডেল করার কাজ করা হয়। বিপরীতে, "--opt মান" এর সাথে যুক্তির নামটি "অপ্ট" এবং কমান্ড লাইনে পরবর্তী মান সরবরাহ করার চ্যালেঞ্জ আমাদের রয়েছে। সেখানেই @ আরভিড অনুরোধ অপ্রত্যক্ষ রেফারেন্স reference {! OPTIND OP ব্যবহার করেছেন। আমি এখনও বুঝতে পারি না, ঠিক আছে, এবং বাশফাকের মন্তব্যে সেই স্টাইলের বিরুদ্ধে সতর্কতা রয়েছে বলে মনে হচ্ছে ( http://mywiki.wooledge.org/BashFAQ/006 )। বিটিডাব্লু, আমি মনে করি না যে পূর্বের পোস্টারের মন্তব্যগুলি OPTIND = $ (($ OPTIND + 1)) এর গুরুত্ব সম্পর্কে সঠিক। আমি বলতে চাইছি,

এই স্ক্রিপ্টের নতুন সংস্করণে, পতাকা -v অর্থ VERBOSE প্রিন্টআউট।

এটি "ক্লাইভ 5.sh" নামক একটি ফাইলে সংরক্ষণ করুন, সম্পাদনযোগ্য করুন এবং এর মধ্যে যে কোনওটি কাজ করবে, বা পছন্দসই পদ্ধতিতে ব্যর্থ হবে

./cli-5.sh  -v --loglevel=44 --toc  TRUE
./cli-5.sh  -v --loglevel=44 --toc=TRUE
./cli-5.sh --loglevel 7
./cli-5.sh --loglevel=8
./cli-5.sh -l9

./cli-5.sh  --toc FALSE --loglevel=77
./cli-5.sh  --toc=FALSE --loglevel=77

./cli-5.sh   -l99 -t yyy
./cli-5.sh   -l 99 -t yyy

এখানে ব্যবহারকারী ইন্টপুতে ত্রুটি-পরীক্ষার উদাহরণ আউটপুট

$ ./cli-5.sh  --toc --loglevel=77
ERROR: toc value must not have dash at beginning
$ ./cli-5.sh  --toc= --loglevel=77
ERROR: value for toc undefined

আপনার -v চালু করা বিবেচনা করা উচিত, কারণ এটি অপটিআইএনডি এবং অপ্টগার্টের অভ্যন্তরীণ প্রিন্ট করে

#/usr/bin/env bash

## Paul Johnson
## 20171016
##

## Combines ideas from
## /programming/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options
## by @Arvid Requate, and http://mwiki.wooledge.org/BashFAQ/035

# What I don't understand yet: 
# In @Arvid REquate's answer, we have 
# val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
# this works, but I don't understand it!


die() {
    printf '%s\n' "$1" >&2
    exit 1
}

printparse(){
    if [ ${VERBOSE} -gt 0 ]; then
        printf 'Parse: %s%s%s\n' "$1" "$2" "$3" >&2;
    fi
}

showme(){
    if [ ${VERBOSE} -gt 0 ]; then
        printf 'VERBOSE: %s\n' "$1" >&2;
    fi
}


VERBOSE=0
loglevel=0
toc="TRUE"

optspec=":vhl:t:-:"
while getopts "$optspec" OPTCHAR; do

    showme "OPTARG:  ${OPTARG[*]}"
    showme "OPTIND:  ${OPTIND[*]}"
    case "${OPTCHAR}" in
        -)
            case "${OPTARG}" in
                loglevel) #argument has no equal sign
                    opt=${OPTARG}
                    val="${!OPTIND}"
                    ## check value. If negative, assume user forgot value
                    showme "OPTIND is {$OPTIND} {!OPTIND} has value \"${!OPTIND}\""
                    if [[ "$val" == -* ]]; then
                        die "ERROR: $opt value must not have dash at beginning"
                    fi
                    ## OPTIND=$(( $OPTIND + 1 )) # CAUTION! no effect?
                    printparse "--${OPTARG}" "  " "${val}"
                    loglevel="${val}"
                    shift
                    ;;
                loglevel=*) #argument has equal sign
                    opt=${OPTARG%=*}
                    val=${OPTARG#*=}
                    if [ "${OPTARG#*=}" ]; then
                        printparse "--${opt}" "=" "${val}"
                        loglevel="${val}"
                        ## shift CAUTION don't shift this, fails othewise
                    else
                        die "ERROR: $opt value must be supplied"
                    fi
                    ;;
                toc) #argument has no equal sign
                    opt=${OPTARG}
                    val="${!OPTIND}"
                    ## check value. If negative, assume user forgot value
                    showme "OPTIND is {$OPTIND} {!OPTIND} has value \"${!OPTIND}\""
                    if [[ "$val" == -* ]]; then
                        die "ERROR: $opt value must not have dash at beginning"
                    fi
                    ## OPTIND=$(( $OPTIND + 1 )) #??
                    printparse "--${opt}" " " "${val}"
                    toc="${val}"
                    shift
                    ;;
                toc=*) #argument has equal sign
                    opt=${OPTARG%=*}
                    val=${OPTARG#*=}
                    if [ "${OPTARG#*=}" ]; then
                        toc=${val}
                        printparse "--$opt" " -> " "$toc"
                        ##shift ## NO! dont shift this
                    else
                        die "ERROR: value for $opt undefined"
                    fi
                    ;;

                help)
                    echo "usage: $0 [-v] [--loglevel[=]<value>] [--toc[=]<TRUE,FALSE>]" >&2
                    exit 2
                    ;;
                *)
                    if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
                        echo "Unknown option --${OPTARG}" >&2
                    fi
                    ;;
            esac;;
        h|-\?|--help)
            ## must rewrite this for all of the arguments
            echo "usage: $0 [-v] [--loglevel[=]<value>] [--toc[=]<TRUE,FALSE>]" >&2
            exit 2
            ;;
        l)
            loglevel=${OPTARG}
            printparse "-l" " "  "${loglevel}"
            ;;
        t)
            toc=${OPTARG}
            ;;
        v)
            VERBOSE=1
            ;;

        *)
            if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
                echo "Non-option argument: '-${OPTARG}'" >&2
            fi
            ;;
    esac
done



echo "
After Parsing values
"
echo "loglevel  $loglevel" 
echo "toc  $toc"

OPTIND=$(( $OPTIND + 1 )): যখনই আপনি অপটিআইএনডি'র প্যারামিটারটি 'গাব্বল' করেন তখন এটি প্রয়োজন (উদাহরণস্বরূপ: যখন একটি ব্যবহৃত হয় --toc value : মান প্যারামিটার সংখ্যায় থাকে $ অপটিন্ড। একবার আপনি টোকের মানটির জন্য এটি পুনরুদ্ধার করার পরে, আপনাকে গোটপটসকে জানিয়ে দেওয়া উচিত যে পার্স করার পরবর্তী প্যারামিটারটি মান নয়, তবে এর পরে একটি (সুতরাং: OPTIND=$(( $OPTIND + 1 )) এবং আপনার স্ক্রিপ্ট (পাশাপাশি আপনি বর্ণিত স্ক্রিপ্ট) অনুপস্থিত রয়েছে: সম্পন্ন হওয়ার পরে: shift $(( $OPTIND -1 ))(অপটেন্ড -১ এ প্যারামিটার 1 পার্স করার পরে গিওপগুলি প্রস্থান করায় আপনাকে তাদের এখান থেকে সরিয়ে নিতে হবে $@এখন যে কোনও "অপশন নেই" পরামিতি রয়েছে
অলিভিয়ার ডুলাক

ওহ, আপনি নিজেকে স্থানান্তরিত করার সময়, আপনি গিওপ্টগুলির নীচে প্যারামিটারগুলি "শিফট" করেন, সুতরাং অপটিআইএনডি সর্বদা সঠিক জিনিসটি নির্দেশ করে ... তবে আমি এটি খুব বিভ্রান্তিকর বলে মনে করি। আমি বিশ্বাস করি (এই মুহুর্তে আপনার স্ক্রিপ্টটি পরীক্ষা করতে পারবেন না) লুপ চলাকালীন আপনার আরও পরে শিফট $ (($ অপ্টিন্ড - 1)) প্রয়োজন, যাতে $ 1 এখন মূল $ 1 (একটি বিকল্প) দিকে নির্দেশ না করে তবে বাকি আর্গুমেন্টগুলির প্রথমটিতে (সমস্ত বিকল্প এবং তাদের মানগুলির সাথে যারা আসছেন) উদাহরণস্বরূপ: myrm -foo -bar = বাজ থারথিসোন তেতানথর অন্য
অলিভিয়ার

5

চাকার আরও একটি সংস্করণ আবিষ্কার করা হচ্ছে ...

এই ফাংশনটি GNU getopt এর জন্য একটি (আশাবাদী) পসিক্স-সামঞ্জস্যপূর্ণ প্লেইন বোর্ন শেল প্রতিস্থাপন। এটি সংক্ষিপ্ত / দীর্ঘ বিকল্পগুলিকে সমর্থন করে যা বাধ্যতামূলক / alচ্ছিক / কোন যুক্তি গ্রহণ করতে পারে এবং বিকল্পগুলি যেভাবে নির্দিষ্ট করা হয়েছে তা জিএনইউ গিওপ্টের মতো প্রায় একই, সুতরাং রূপান্তরটি তুচ্ছ।

অবশ্যই এটি কোনও স্ক্রিপ্টে ফেলে দেওয়ার জন্য কোডের একটি বৃহত আকার, তবে এটি সুপরিচিত getopt_long শেল ফাংশনের প্রায় অর্ধেক রেখা, এবং আপনি কেবলমাত্র বিদ্যমান GNU getopt ব্যবহারগুলি প্রতিস্থাপন করতে চান এমন ক্ষেত্রে পছন্দসই হতে পারে।

এটি বেশ নতুন কোড, তাই ওয়াইএমএমভি (এবং অবশ্যই দয়া করে আমাকে জানান যে এটি কোনও কারণে পসিক্সের সাথে সামঞ্জস্যপূর্ণ নয় - বহনযোগ্যতা শুরু থেকেই অভিপ্রায় ছিল, তবে আমার কোনও পসিক্স পরীক্ষার পরিবেশ নেই)।

কোড এবং উদাহরণ ব্যবহার অনুসরণ:

#!/bin/sh
# posix_getopt shell function
# Author: Phil S.
# Version: 1.0
# Created: 2016-07-05
# URL: http://stackoverflow.com/a/37087374/324105

# POSIX-compatible argument quoting and parameter save/restore
# http://www.etalabs.net/sh_tricks.html
# Usage:
# parameters=$(save "$@") # save the original parameters.
# eval "set -- ${parameters}" # restore the saved parameters.
save () {
    local param
    for param; do
        printf %s\\n "$param" \
            | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"
    done
    printf %s\\n " "
}

# Exit with status $1 after displaying error message $2.
exiterr () {
    printf %s\\n "$2" >&2
    exit $1
}

# POSIX-compatible command line option parsing.
# This function supports long options and optional arguments, and is
# a (largely-compatible) drop-in replacement for GNU getopt.
#
# Instead of:
# opts=$(getopt -o "$shortopts" -l "$longopts" -- "$@")
# eval set -- ${opts}
#
# We instead use:
# opts=$(posix_getopt "$shortopts" "$longopts" "$@")
# eval "set -- ${opts}"
posix_getopt () { # args: "$shortopts" "$longopts" "$@"
    local shortopts longopts \
          arg argtype getopt nonopt opt optchar optword suffix

    shortopts="$1"
    longopts="$2"
    shift 2

    getopt=
    nonopt=
    while [ $# -gt 0 ]; do
        opt=
        arg=
        argtype=
        case "$1" in
            # '--' means don't parse the remaining options
            ( -- ) {
                getopt="${getopt}$(save "$@")"
                shift $#
                break
            };;
            # process short option
            ( -[!-]* ) {         # -x[foo]
                suffix=${1#-?}   # foo
                opt=${1%$suffix} # -x
                optchar=${opt#-} # x
                case "${shortopts}" in
                    ( *${optchar}::* ) { # optional argument
                        argtype=optional
                        arg="${suffix}"
                        shift
                    };;
                    ( *${optchar}:* ) { # required argument
                        argtype=required
                        if [ -n "${suffix}" ]; then
                            arg="${suffix}"
                            shift
                        else
                            case "$2" in
                                ( -* ) exiterr 1 "$1 requires an argument";;
                                ( ?* ) arg="$2"; shift 2;;
                                (  * ) exiterr 1 "$1 requires an argument";;
                            esac
                        fi
                    };;
                    ( *${optchar}* ) { # no argument
                        argtype=none
                        arg=
                        shift
                        # Handle multiple no-argument parameters combined as
                        # -xyz instead of -x -y -z. If we have just shifted
                        # parameter -xyz, we now replace it with -yz (which
                        # will be processed in the next iteration).
                        if [ -n "${suffix}" ]; then
                            eval "set -- $(save "-${suffix}")$(save "$@")"
                        fi
                    };;
                    ( * ) exiterr 1 "Unknown option $1";;
                esac
            };;
            # process long option
            ( --?* ) {            # --xarg[=foo]
                suffix=${1#*=}    # foo (unless there was no =)
                if [ "${suffix}" = "$1" ]; then
                    suffix=
                fi
                opt=${1%=$suffix} # --xarg
                optword=${opt#--} # xarg
                case ",${longopts}," in
                    ( *,${optword}::,* ) { # optional argument
                        argtype=optional
                        arg="${suffix}"
                        shift
                    };;
                    ( *,${optword}:,* ) { # required argument
                        argtype=required
                        if [ -n "${suffix}" ]; then
                            arg="${suffix}"
                            shift
                        else
                            case "$2" in
                                ( -* ) exiterr 1 \
                                       "--${optword} requires an argument";;
                                ( ?* ) arg="$2"; shift 2;;
                                (  * ) exiterr 1 \
                                       "--${optword} requires an argument";;
                            esac
                        fi
                    };;
                    ( *,${optword},* ) { # no argument
                        if [ -n "${suffix}" ]; then
                            exiterr 1 "--${optword} does not take an argument"
                        fi
                        argtype=none
                        arg=
                        shift
                    };;
                    ( * ) exiterr 1 "Unknown option $1";;
                esac
            };;
            # any other parameters starting with -
            ( -* ) exiterr 1 "Unknown option $1";;
            # remember non-option parameters
            ( * ) nonopt="${nonopt}$(save "$1")"; shift;;
        esac

        if [ -n "${opt}" ]; then
            getopt="${getopt}$(save "$opt")"
            case "${argtype}" in
                ( optional|required ) {
                    getopt="${getopt}$(save "$arg")"
                };;
            esac
        fi
    done

    # Generate function output, suitable for:
    # eval "set -- $(posix_getopt ...)"
    printf %s "${getopt}"
    if [ -n "${nonopt}" ]; then
        printf %s "$(save "--")${nonopt}"
    fi
}

ব্যবহারের উদাহরণ:

# Process command line options
shortopts="hvd:c::s::L:D"
longopts="help,version,directory:,client::,server::,load:,delete"
#opts=$(getopt -o "$shortopts" -l "$longopts" -n "$(basename $0)" -- "$@")
opts=$(posix_getopt "$shortopts" "$longopts" "$@")
if [ $? -eq 0 ]; then
    #eval set -- ${opts}
    eval "set -- ${opts}"
    while [ $# -gt 0 ]; do
        case "$1" in
            ( --                ) shift; break;;
            ( -h|--help         ) help=1; shift; break;;
            ( -v|--version      ) version_help=1; shift; break;;
            ( -d|--directory    ) dir=$2; shift 2;;
            ( -c|--client       ) useclient=1; client=$2; shift 2;;
            ( -s|--server       ) startserver=1; server_name=$2; shift 2;;
            ( -L|--load         ) load=$2; shift 2;;
            ( -D|--delete       ) delete=1; shift;;
        esac
    done
else
    shorthelp=1 # getopt returned (and reported) an error.
fi

4

গৃহীত উত্তরটি অন্তর্নির্মিত বাশের সমস্ত ত্রুটিগুলি দেখানোর জন্য খুব সুন্দর কাজ করে getopts। উত্তরটি এর সাথে শেষ হয়:

সুতরাং লম্বা বিকল্পগুলির পক্ষে সমর্থনগুলির অভাবের আশেপাশে কাজ করার জন্য আরও কোড লেখা সম্ভব হলেও এটি অনেক বেশি কাজ এবং আপনার কোডটি সহজ করার জন্য একটি গিওপ্ট পার্সার ব্যবহারের উদ্দেশ্যটিকে আংশিকভাবে পরাস্ত করে।

এবং যদিও আমি এই উক্তিটির সাথে নীতিগতভাবে একমত হই, তবুও আমি অনুভব করি যে আমরা সকলেই বিভিন্ন স্ক্রিপ্টে এই বৈশিষ্ট্যটি কতবার প্রয়োগ করেছি একটি "মানকৃত", ভাল পরীক্ষিত সমাধান তৈরিতে কিছুটা প্রচেষ্টা চালিয়ে যাওয়াকে ন্যায্যতা দেয়।

যেমন, আমি কোনও বাহ্যিক নির্ভরতা ছাড়াই খাঁটি বাশে getoptsপ্রয়োগ করে বাশকে "আপগ্রেড" করেছি getopts_long। ফাংশনটির ব্যবহার অন্তর্নির্মিত সাথে 100% সামঞ্জস্যপূর্ণ getopts

অন্তর্ভুক্ত করে getopts_long(যা হয় GitHub থেকে হোস্ট করা একটি স্ক্রিপ্ট মধ্যে), মূল প্রশ্নের উত্তর কেবল হিসাবে হিসাবে প্রয়োগ করা যেতে পারে:

source "${PATH_TO}/getopts_long.bash"

while getopts_long ':c: copyfile:' OPTKEY; do
    case ${OPTKEY} in
        'c'|'copyfile')
            echo 'file supplied -- ${OPTARG}'
            ;;
        '?')
            echo "INVALID OPTION -- ${OPTARG}" >&2
            exit 1
            ;;
        ':')
            echo "MISSING ARGUMENT for option -- ${OPTARG}" >&2
            exit 1
            ;;
        *)
            echo "Misconfigured OPTSPEC or uncaught option -- ${OPTKEY}" >&2
            exit 1
            ;;
    esac
done

shift $(( OPTIND - 1 ))
[[ "${1}" == "--" ]] && shift

3

তার সমাধান সম্পর্কে মন্তব্য করার জন্য বা ভোট দেওয়ার পক্ষে আমার কাছে এখনও পর্যাপ্ত পরিমাণ নেই, তবে গন্ধের উত্তর আমার পক্ষে অত্যন্ত ভাল কাজ করেছে। আমি যে বিষয়টি নিয়েই ছড়িয়ে পড়েছিলাম তা হ'ল আর্গুমেন্টগুলি সিঙ্গেল-কোটসে জড়িয়ে যায় (তাই আমার এগুলির একটি স্ট্রিপ রয়েছে)।

আমি কিছু উদাহরণ ব্যবহার এবং সহায়তা পাঠ্যও যুক্ত করেছি। আমি আমার সামান্য বর্ধিত সংস্করণ এখানে অন্তর্ভুক্ত করব:

#!/bin/bash

# getopt example
# from: /programming/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options
HELP_TEXT=\
"   USAGE:\n
    Accepts - and -- flags, can specify options that require a value, and can be in any order. A double-hyphen (--) will stop processing options.\n\n

    Accepts the following forms:\n\n

    getopt-example.sh -a -b -c value-for-c some-arg\n
    getopt-example.sh -c value-for-c -a -b some-arg\n
    getopt-example.sh -abc some-arg\n
    getopt-example.sh --along --blong --clong value-for-c -a -b -c some-arg\n
    getopt-example.sh some-arg --clong value-for-c\n
    getopt-example.sh
"

aflag=false
bflag=false
cargument=""

# options may be followed by one colon to indicate they have a required argument
if ! options=$(getopt -o abc:h\? -l along,blong,help,clong: -- "$@")
then
    # something went wrong, getopt will put out an error message for us
    exit 1
fi

set -- $options

while [ $# -gt 0 ]
do
    case $1 in
    -a|--along) aflag=true ;;
    -b|--blong) bflag=true ;;
    # for options with required arguments, an additional shift is required
    -c|--clong) cargument="$2" ; shift;;
    -h|--help|-\?) echo -e $HELP_TEXT; exit;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*) break;;
    esac
    shift
done

# to remove the single quotes around arguments, pipe the output into:
# | sed -e "s/^'\\|'$//g"  (just leading/trailing) or | sed -e "s/'//g"  (all)

echo aflag=${aflag}
echo bflag=${bflag}
echo cargument=${cargument}

while [ $# -gt 0 ]
do
    echo arg=$1
    shift

    if [[ $aflag == true ]]; then
        echo a is true
    fi

done

3

বাশে পার্সিংয়ের জটিল বিকল্পের জন্য আপনি কয়েকটি আলাদা পদ্ধতির সন্ধান করতে পারেন: http://mywiki.wooledge.org/ComplexOptionParsing

আমি নিম্নলিখিতটি তৈরি করেছি এবং আমি মনে করি এটি একটি ভাল, কারণ এটি ন্যূনতম কোড এবং দীর্ঘ এবং সংক্ষিপ্ত বিকল্প উভয়ই কাজ করে। একটি দীর্ঘ বিকল্পের এই পদ্ধতির সাথে একাধিক যুক্তিও থাকতে পারে।

#!/bin/bash
# Uses bash extensions.  Not portable as written.

declare -A longoptspec
longoptspec=( [loglevel]=1 ) #use associative array to declare how many arguments a long option expects, in this case we declare that loglevel expects/has one argument, long options that aren't listed i n this way will have zero arguments by default
optspec=":h-:"
while getopts "$optspec" opt; do
while true; do
    case "${opt}" in
        -) #OPTARG is name-of-long-option or name-of-long-option=value
            if [[ "${OPTARG}" =~ .*=.* ]] #with this --key=value format only one argument is possible
            then
                opt=${OPTARG/=*/}
                OPTARG=${OPTARG#*=}
                ((OPTIND--))    
            else #with this --key value1 value2 format multiple arguments are possible
                opt="$OPTARG"
                OPTARG=(${@:OPTIND:$((longoptspec[$opt]))})
            fi
            ((OPTIND+=longoptspec[$opt]))
            continue #now that opt/OPTARG are set we can process them as if getopts would've given us long options
            ;;
        loglevel)
          loglevel=$OPTARG
            ;;
        h|help)
            echo "usage: $0 [--loglevel[=]<value>]" >&2
            exit 2
            ;;
    esac
break; done
done

# End of file

2

আমি দীর্ঘদিন ধরে এই বিষয়ে কাজ করে চলেছি ... এবং আমার নিজস্ব লাইব্রেরি তৈরি করেছি যা আপনার মূল স্ক্রিপ্টে আপনার উত্সের প্রয়োজন হবে। উদাহরণের জন্য libopt4shell এবং cd2mpc দেখুন । আশা করি এটা সাহায্য করবে !


2

একটি উন্নত সমাধান:

# translate long options to short
# Note: This enable long options but disable "--?*" in $OPTARG, or disable long options after  "--" in option fields.
for ((i=1;$#;i++)) ; do
    case "$1" in
        --)
            # [ ${args[$((i-1))]} == ... ] || EndOpt=1 ;;& # DIRTY: we still can handle some execptions...
            EndOpt=1 ;;&
        --version) ((EndOpt)) && args[$i]="$1"  || args[$i]="-V";;
        # default case : short option use the first char of the long option:
        --?*) ((EndOpt)) && args[$i]="$1"  || args[$i]="-${1:2:1}";;
        # pass through anything else:
        *) args[$i]="$1" ;;
    esac
    shift
done
# reset the translated args
set -- "${args[@]}"

function usage {
echo "Usage: $0 [options] files" >&2
    exit $1
}

# now we can process with getopt
while getopts ":hvVc:" opt; do
    case $opt in
        h)  usage ;;
        v)  VERBOSE=true ;;
        V)  echo $Version ; exit ;;
        c)  source $OPTARG ;;
        \?) echo "unrecognized option: -$opt" ; usage -1 ;;
        :)
        echo "option -$OPTARG requires an argument"
        usage -1
        ;;
    esac
done

shift $((OPTIND-1))
[[ "$1" == "--" ]] && shift

2

সম্ভবত এটি খুব সহজ কমান্ড লাইন বিকল্পের প্রয়োজন হলে, কেবল গিওপ্টস অংশের জন্য, কেএসএস ব্যবহার করা সহজ, কারণ এটি আরও সহজেই করা যায়।

# Working Getopts Long => KSH

#! /bin/ksh
# Getopts Long
USAGE="s(showconfig)"
USAGE+="c:(createdb)"
USAGE+="l:(createlistener)"
USAGE+="g:(generatescripts)"
USAGE+="r:(removedb)"
USAGE+="x:(removelistener)"
USAGE+="t:(createtemplate)"
USAGE+="h(help)"

while getopts "$USAGE" optchar ; do
    case $optchar in
    s)  echo "Displaying Configuration" ;;
        c)  echo "Creating Database $OPTARG" ;;
    l)  echo "Creating Listener LISTENER_$OPTARG" ;;
    g)  echo "Generating Scripts for Database $OPTARG" ;;
    r)  echo "Removing Database $OPTARG" ;;
    x)  echo "Removing Listener LISTENER_$OPTARG" ;;
    t)  echo "Creating Database Template" ;;
    h)  echo "Help" ;;
    esac
done

+1 - নোট করুন যে এটি ksh93-এ সীমাবদ্ধ - ওপেন সোর্স এএসটি প্রকল্প (এটিএন্ডটি গবেষণা) থেকে।
হেন্ক ল্যাঙ্গভেল্ড

2

কঠোর বাশ সমর্থন (-u) সহ আমি বাহ্যিক নির্ভরতা ছাড়াই কিছু চাইছিলাম এবং পুরানো বাশ সংস্করণেও এটি কাজ করা আমার দরকার ছিল। এটি বিভিন্ন ধরণের প্যারাম পরিচালনা করে:

  • সংক্ষিপ্ত bools (-h)
  • সংক্ষিপ্ত বিকল্পগুলি (-i "image.jpg")
  • দীর্ঘ বাল (- সাহায্য)
  • সমান বিকল্পসমূহ (--file = "filename.ext")
  • স্থান বিকল্প (--file "filename.ext")
  • সংক্ষিপ্ত bools (-hvm)

আপনার স্ক্রিপ্টের শীর্ষে কেবল নিম্নলিখিতটি প্রবেশ করান:

# Check if a list of params contains a specific param
# usage: if _param_variant "h|?|help p|path f|file long-thing t|test-thing" "file" ; then ...
# the global variable $key is updated to the long notation (last entry in the pipe delineated list, if applicable)
_param_variant() {
  for param in $1 ; do
    local variants=${param//\|/ }
    for variant in $variants ; do
      if [[ "$variant" = "$2" ]] ; then
        # Update the key to match the long version
        local arr=(${param//\|/ })
        let last=${#arr[@]}-1
        key="${arr[$last]}"
        return 0
      fi
    done
  done
  return 1
}

# Get input parameters in short or long notation, with no dependencies beyond bash
# usage:
#     # First, set your defaults
#     param_help=false
#     param_path="."
#     param_file=false
#     param_image=false
#     param_image_lossy=true
#     # Define allowed parameters
#     allowed_params="h|?|help p|path f|file i|image image-lossy"
#     # Get parameters from the arguments provided
#     _get_params $*
#
# Parameters will be converted into safe variable names like:
#     param_help,
#     param_path,
#     param_file,
#     param_image,
#     param_image_lossy
#
# Parameters without a value like "-h" or "--help" will be treated as
# boolean, and will be set as param_help=true
#
# Parameters can accept values in the various typical ways:
#     -i "path/goes/here"
#     --image "path/goes/here"
#     --image="path/goes/here"
#     --image=path/goes/here
# These would all result in effectively the same thing:
#     param_image="path/goes/here"
#
# Concatinated short parameters (boolean) are also supported
#     -vhm is the same as -v -h -m
_get_params(){

  local param_pair
  local key
  local value
  local shift_count

  while : ; do
    # Ensure we have a valid param. Allows this to work even in -u mode.
    if [[ $# == 0 || -z $1 ]] ; then
      break
    fi

    # Split the argument if it contains "="
    param_pair=(${1//=/ })
    # Remove preceeding dashes
    key="${param_pair[0]#--}"

    # Check for concatinated boolean short parameters.
    local nodash="${key#-}"
    local breakout=false
    if [[ "$nodash" != "$key" && ${#nodash} -gt 1 ]]; then
      # Extrapolate multiple boolean keys in single dash notation. ie. "-vmh" should translate to: "-v -m -h"
      local short_param_count=${#nodash}
      let new_arg_count=$#+$short_param_count-1
      local new_args=""
      # $str_pos is the current position in the short param string $nodash
      for (( str_pos=0; str_pos<new_arg_count; str_pos++ )); do
        # The first character becomes the current key
        if [ $str_pos -eq 0 ] ; then
          key="${nodash:$str_pos:1}"
          breakout=true
        fi
        # $arg_pos is the current position in the constructed arguments list
        let arg_pos=$str_pos+1
        if [ $arg_pos -gt $short_param_count ] ; then
          # handle other arguments
          let orignal_arg_number=$arg_pos-$short_param_count+1
          local new_arg="${!orignal_arg_number}"
        else
          # break out our one argument into new ones
          local new_arg="-${nodash:$str_pos:1}"
        fi
        new_args="$new_args \"$new_arg\""
      done
      # remove the preceding space and set the new arguments
      eval set -- "${new_args# }"
    fi
    if ! $breakout ; then
      key="$nodash"
    fi

    # By default we expect to shift one argument at a time
    shift_count=1
    if [ "${#param_pair[@]}" -gt "1" ] ; then
      # This is a param with equals notation
      value="${param_pair[1]}"
    else
      # This is either a boolean param and there is no value,
      # or the value is the next command line argument
      # Assume the value is a boolean true, unless the next argument is found to be a value.
      value=true
      if [[ $# -gt 1 && -n "$2" ]]; then
        local nodash="${2#-}"
        if [ "$nodash" = "$2" ]; then
          # The next argument has NO preceding dash so it is a value
          value="$2"
          shift_count=2
        fi
      fi
    fi

    # Check that the param being passed is one of the allowed params
    if _param_variant "$allowed_params" "$key" ; then
      # --key-name will now become param_key_name
      eval param_${key//-/_}="$value"
    else
      printf 'WARNING: Unknown option (ignored): %s\n' "$1" >&2
    fi
    shift $shift_count
  done
}

এবং এটি এর মতো ব্যবহার করুন:

# Assign defaults for parameters
param_help=false
param_path=$(pwd)
param_file=false
param_image=true
param_image_lossy=true
param_image_lossy_quality=85

# Define the params we will allow
allowed_params="h|?|help p|path f|file i|image image-lossy image-lossy-quality"

# Get the params from arguments provided
_get_params $*

1

ক্রস প্ল্যাটফর্মের সাথে সামঞ্জস্যপূর্ণ থাকতে এবং বাহ্যিক এক্সিকিউটেবলের উপর নির্ভরতা এড়াতে, আমি অন্য ভাষা থেকে কিছু কোড পোর্ট করেছি।

আমি এটি ব্যবহার করা খুব সহজ বলে মনে করি, এখানে একটি উদাহরণ রয়েছে:

ArgParser::addArg "[h]elp"    false    "This list"
ArgParser::addArg "[q]uiet"   false    "Supress output"
ArgParser::addArg "[s]leep"   1        "Seconds to sleep"
ArgParser::addArg "v"         1        "Verbose mode"

ArgParser::parse "$@"

ArgParser::isset help && ArgParser::showArgs

ArgParser::isset "quiet" \
   && echo "Quiet!" \
   || echo "Noisy!"

local __sleep
ArgParser::tryAndGetArg sleep into __sleep \
   && echo "Sleep for $__sleep seconds" \
   || echo "No value passed for sleep"

# This way is often more convienient, but is a little slower
echo "Sleep set to: $( ArgParser::getArg sleep )"

প্রয়োজনীয় BASH এটির চেয়ে সামান্য দীর্ঘ, তবে আমি BASH 4 এর সহযোগী অ্যারেগুলির উপর নির্ভরতা এড়াতে চেয়েছিলাম। আপনি এটি http://nt4.com/bash/argparser.inc.sh থেকে সরাসরি ডাউনলোড করতে পারেন

#!/usr/bin/env bash

# Updates to this script may be found at
# http://nt4.com/bash/argparser.inc.sh

# Example of runtime usage:
# mnc.sh --nc -q Caprica.S0*mkv *.avi *.mp3 --more-options here --host centos8.host.com

# Example of use in script (see bottom)
# Just include this file in yours, or use
# source argparser.inc.sh

unset EXPLODED
declare -a EXPLODED
function explode 
{
    local c=$# 
    (( c < 2 )) && 
    {
        echo function "$0" is missing parameters 
        return 1
    }

    local delimiter="$1"
    local string="$2"
    local limit=${3-99}

    local tmp_delim=$'\x07'
    local delin=${string//$delimiter/$tmp_delim}
    local oldifs="$IFS"

    IFS="$tmp_delim"
    EXPLODED=($delin)
    IFS="$oldifs"
}


# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
# Usage: local "$1" && upvar $1 "value(s)"
upvar() {
    if unset -v "$1"; then           # Unset & validate varname
        if (( $# == 2 )); then
            eval $1=\"\$2\"          # Return single value
        else
            eval $1=\(\"\${@:2}\"\)  # Return array
        fi
    fi
}

function decho
{
    :
}

function ArgParser::check
{
    __args=${#__argparser__arglist[@]}
    for (( i=0; i<__args; i++ ))
    do
        matched=0
        explode "|" "${__argparser__arglist[$i]}"
        if [ "${#1}" -eq 1 ]
        then
            if [ "${1}" == "${EXPLODED[0]}" ]
            then
                decho "Matched $1 with ${EXPLODED[0]}"
                matched=1

                break
            fi
        else
            if [ "${1}" == "${EXPLODED[1]}" ]
            then
                decho "Matched $1 with ${EXPLODED[1]}"
                matched=1

                break
            fi
        fi
    done
    (( matched == 0 )) && return 2
    # decho "Key $key has default argument of ${EXPLODED[3]}"
    if [ "${EXPLODED[3]}" == "false" ]
    then
        return 0
    else
        return 1
    fi
}

function ArgParser::set
{
    key=$3
    value="${1:-true}"
    declare -g __argpassed__$key="$value"
}

function ArgParser::parse
{

    unset __argparser__argv
    __argparser__argv=()
    # echo parsing: "$@"

    while [ -n "$1" ]
    do
        # echo "Processing $1"
        if [ "${1:0:2}" == '--' ]
        then
            key=${1:2}
            value=$2
        elif [ "${1:0:1}" == '-' ]
        then
            key=${1:1}               # Strip off leading -
            value=$2
        else
            decho "Not argument or option: '$1'" >& 2
            __argparser__argv+=( "$1" )
            shift
            continue
        fi
        # parameter=${tmp%%=*}     # Extract name.
        # value=${tmp##*=}         # Extract value.
        decho "Key: '$key', value: '$value'"
        # eval $parameter=$value
        ArgParser::check $key
        el=$?
        # echo "Check returned $el for $key"
        [ $el -eq  2 ] && decho "No match for option '$1'" >&2 # && __argparser__argv+=( "$1" )
        [ $el -eq  0 ] && decho "Matched option '${EXPLODED[2]}' with no arguments"        >&2 && ArgParser::set true "${EXPLODED[@]}"
        [ $el -eq  1 ] && decho "Matched option '${EXPLODED[2]}' with an argument of '$2'"   >&2 && ArgParser::set "$2" "${EXPLODED[@]}" && shift
        shift
    done
}

function ArgParser::isset
{
    declare -p "__argpassed__$1" > /dev/null 2>&1 && return 0
    return 1
}

function ArgParser::getArg
{
    # This one would be a bit silly, since we can only return non-integer arguments ineffeciently
    varname="__argpassed__$1"
    echo "${!varname}"
}

##
# usage: tryAndGetArg <argname> into <varname>
# returns: 0 on success, 1 on failure
function ArgParser::tryAndGetArg
{
    local __varname="__argpassed__$1"
    local __value="${!__varname}"
    test -z "$__value" && return 1
    local "$3" && upvar $3 "$__value"
    return 0
}

function ArgParser::__construct
{
    unset __argparser__arglist
    # declare -a __argparser__arglist
}

##
# @brief add command line argument
# @param 1 short and/or long, eg: [s]hort
# @param 2 default value
# @param 3 description
##
function ArgParser::addArg
{
    # check for short arg within long arg
    if [[ "$1" =~ \[(.)\] ]]
    then
        short=${BASH_REMATCH[1]}
        long=${1/\[$short\]/$short}
    else
        long=$1
    fi
    if [ "${#long}" -eq 1 ]
    then
        short=$long
        long=''
    fi
    decho short: "$short"
    decho long: "$long"
    __argparser__arglist+=("$short|$long|$1|$2|$3")
}

## 
# @brief show available command line arguments
##
function ArgParser::showArgs
{
    # declare -p | grep argparser
    printf "Usage: %s [OPTION...]\n\n" "$( basename "${BASH_SOURCE[0]}" )"
    printf "Defaults for the options are specified in brackets.\n\n";

    __args=${#__argparser__arglist[@]}
    for (( i=0; i<__args; i++ ))
    do
        local shortname=
        local fullname=
        local default=
        local description=
        local comma=

        explode "|" "${__argparser__arglist[$i]}"

        shortname="${EXPLODED[0]:+-${EXPLODED[0]}}" # String Substitution Guide: 
        fullname="${EXPLODED[1]:+--${EXPLODED[1]}}" # http://tldp.org/LDP/abs/html/parameter-substitution.html
        test -n "$shortname" \
            && test -n "$fullname" \
            && comma=","

        default="${EXPLODED[3]}"
        case $default in
            false )
                default=
                ;;
            "" )
                default=
                ;;
            * )
                default="[$default]"
        esac

        description="${EXPLODED[4]}"

        printf "  %2s%1s %-19s %s %s\n" "$shortname" "$comma" "$fullname" "$description" "$default"
    done
}

function ArgParser::test
{
    # Arguments with a default of 'false' do not take paramaters (note: default
    # values are not applied in this release)

    ArgParser::addArg "[h]elp"      false       "This list"
    ArgParser::addArg "[q]uiet" false       "Supress output"
    ArgParser::addArg "[s]leep" 1           "Seconds to sleep"
    ArgParser::addArg "v"           1           "Verbose mode"

    ArgParser::parse "$@"

    ArgParser::isset help && ArgParser::showArgs

    ArgParser::isset "quiet" \
        && echo "Quiet!" \
        || echo "Noisy!"

    local __sleep
    ArgParser::tryAndGetArg sleep into __sleep \
        && echo "Sleep for $__sleep seconds" \
        || echo "No value passed for sleep"

    # This way is often more convienient, but is a little slower
    echo "Sleep set to: $( ArgParser::getArg sleep )"

    echo "Remaining command line: ${__argparser__argv[@]}"

}

if [ "$( basename "$0" )" == "argparser.inc.sh" ]
then
    ArgParser::test "$@"
fi

1

আপনার সমস্ত দীর্ঘ বিকল্পের যদি স্বতন্ত্র বিকল্প হিসাবে প্রথম অক্ষরগুলি অনন্য এবং মেলাতে থাকে তবে উদাহরণস্বরূপ

./slamm --chaos 23 --plenty test -quiet

হিসাবে একই

./slamm -c 23 -p test -q

আপনি op আরোগুলি পুনরায় লেখার জন্য getopts এর আগে এটি ব্যবহার করতে পারেন :

# change long options to short options

for arg; do 
    [[ "${arg:0:1}" == "-" ]] && delim="" || delim="\""
    if [ "${arg:0:2}" == "--" ]; 
       then args="${args} -${arg:2:1}" 
       else args="${args} ${delim}${arg}${delim}"
    fi
done

# reset the incoming args
eval set -- $args

# proceed as usual
while getopts ":b:la:h" OPTION; do
    .....

অনুপ্রেরণার জন্য এমটিভির জন্য ধন্যবাদ ;-)


আমি এখানে eval এর তাত্পর্যটি পাই না
User.friendly

1

যদি কেবল এইভাবে আপনি স্ক্রিপ্টটি কল করতে চান

myscript.sh --input1 "ABC" --input2 "PQR" --input2 "XYZ"

তারপরে আপনি getopt এবং --longoptions এর সহায়তায় এটি অর্জনের এই সহজতম উপায়টি অনুসরণ করতে পারেন

এটি চেষ্টা করুন, আশা করি এটি দরকারী

# Read command line options
ARGUMENT_LIST=(
    "input1"
    "input2"
    "input3"
)



# read arguments
opts=$(getopt \
    --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \
    --name "$(basename "$0")" \
    --options "" \
    -- "$@"
)


echo $opts

eval set --$opts

while true; do
    case "$1" in
    --input1)  
        shift
        empId=$1
        ;;
    --input2)  
        shift
        fromDate=$1
        ;;
    --input3)  
        shift
        toDate=$1
        ;;
      --)
        shift
        break
        ;;
    esac
    shift
done

0

যতক্ষণ আপনি তাদের তর্ক করার আশা করেন না যতক্ষণ না ল্যাপ বিকল্পগুলি দীর্ঘ বিকল্পগুলি পার্স করার জন্য "ব্যবহৃত হতে পারে" ...

এখানে কীভাবে করবেন:

$ cat > longopt
while getopts 'e:-:' OPT; do
  case $OPT in
    e) echo echo: $OPTARG;;
    -) #long option
       case $OPTARG in
         long-option) echo long option;;
         *) echo long option: $OPTARG;;
       esac;;
  esac
done

$ bash longopt -e asd --long-option --long1 --long2 -e test
echo: asd
long option
long option: long1
long option: long2
echo: test

যদি আপনি দীর্ঘ বিকল্পের জন্য প্যারামিটার পাওয়ার জন্য ওপিটিআইএনডি ব্যবহার করার চেষ্টা করেন, গিওপটগুলি এটিকে প্রথম কোনও alচ্ছিক অবস্থানগত পরামিতি হিসাবে বিবেচনা করবে এবং অন্য কোনও পরামিতি পার্সিং বন্ধ করবে। এ জাতীয় ক্ষেত্রে আপনি সাধারণ কেস স্টেটমেন্ট দিয়ে ম্যানুয়ালি হ্যান্ডেল করে নেওয়া ভাল।

এটি "সর্বদা" কাজ করবে:

$ cat >longopt2
while (($#)); do
    OPT=$1
    shift
    case $OPT in
        --*) case ${OPT:2} in
            long1) echo long1 option;;
            complex) echo comples with argument $1; shift;;
        esac;;

        -*) case ${OPT:1} in
            a) echo short option a;;
            b) echo short option b with parameter $1; shift;;
        esac;;
    esac
done


$ bash longopt2 --complex abc -a --long -b test
comples with argument abc
short option a
short option b with parameter test

যদিও গিওপটসের মতো নমনীয় নয় এবং কেস ইনস্ট্যান্সের মধ্যে আপনাকে নিজেরাই ত্রুটি পরীক্ষা করতে অনেক কিছুই করতে হবে ...

তবে এটি একটি বিকল্প।


তবে দীর্ঘ বিকল্পগুলি প্রায়শই যুক্তি প্রত্যাশা করে। এবং আপনি এর সাথে আরও কিছু করতে পারেন - এটি হ্যাকের কিছু হলেও এটি কাজ করার জন্য। শেষ পর্যন্ত কেউ যুক্তি দিতে পারে যে এটি যদি স্থানীয়ভাবে সমর্থন না করে তবে এটি বাস্তবায়নের প্রতিটি উপায় হ্যাকের কিছু তবে তবুও আপনি এটি প্রসারিত করতে পারেন - খুব বেশি। এবং হ্যাঁ শিফটটি খুব দরকারী তবে অবশ্যই এটি যদি কোনও যুক্তির প্রত্যাশা করে তবে এটি শেষ হতে পারে যে পরবর্তী যুক্তি (যদি ব্যবহারকারী দ্বারা নির্দিষ্ট না করা হয়) প্রত্যাশিত যুক্তির অংশ।
প্রাইফটান

হ্যাঁ, এই দুটি আর্গুমেন্ট নামের যুক্তি ছাড়াই নামগুলির জন্য পোক, আপনার গিওপসের মতো কোনও ধরণের কনফিগারেশন প্রয়োজন। এবং শিফ্ট সম্পর্কিত, আপনি সর্বদা সেট সহ "এটিকে ফিরিয়ে" রাখতে পারেন। যে কোনও ক্ষেত্রে এটি অবশ্যই কনফিগারযোগ্য হবে যদি কোনও প্যারামিটার প্রত্যাশিত হয় বা না হয়। এমনকি আপনি এর জন্য কিছু যাদু ব্যবহার করতে পারেন, তবে তারপরে আপনি ব্যবহারকারীদের ব্যবহার করতে বাধ্য করবেন - যাদুটি থামবে এবং অবস্থানগত পরামিতিগুলি সূচিত হবে তা ইঙ্গিত করতে, যা আরও খারাপ ho
ইস্তানী

যথেষ্ট ফর্সা। এটা যুক্তিসঙ্গত চেয়ে বেশি। Tbh আমি মনে করি না আমি কী নিয়ে চলছিলাম এবং আমি নিজেই এই প্রশ্নটি সম্পর্কে ভুলে গিয়েছিলাম। আমি কেবল অস্পষ্টভাবে মনে করেছিলাম কীভাবে এটি কীভাবে পেলাম। চিয়ার্স। ওহ এবং ধারণার জন্য একটি +1 রাখুন। আপনি প্রচেষ্টার মধ্য দিয়ে গিয়েছিলেন এবং আপনি কী অর্জন করছেন তাও পরিষ্কার করে দিয়েছিলেন। আমি কে প্রচেষ্টার মাধ্যমে যান মানুষ ইত্যাদি অন্যদের ধারনা দিতে সম্মান
Pryftan

0

Builtin getopts শুধুমাত্র পার্স সংক্ষিপ্ত অপশন (ksh93 ছাড়া), কিন্তু আপনি এখনও স্ক্রিপ্টিং এর কয়েক লাইন getopts হ্যান্ডলগুলি দীর্ঘ বিকল্পগুলি যোগ করতে পারেন।

এখানে http://www.uxora.com/unix/shell-script/22-handle-long-options-with-getopts- এ কোডের একটি অংশ পাওয়া গেছে

  #== set short options ==#
SCRIPT_OPTS=':fbF:B:-:h'
  #== set long options associated with short one ==#
typeset -A ARRAY_OPTS
ARRAY_OPTS=(
    [foo]=f
    [bar]=b
    [foobar]=F
    [barfoo]=B
    [help]=h
    [man]=h
)

  #== parse options ==#
while getopts ${SCRIPT_OPTS} OPTION ; do
    #== translate long options to short ==#
    if [[ "x$OPTION" == "x-" ]]; then
        LONG_OPTION=$OPTARG
        LONG_OPTARG=$(echo $LONG_OPTION | grep "=" | cut -d'=' -f2)
        LONG_OPTIND=-1
        [[ "x$LONG_OPTARG" = "x" ]] && LONG_OPTIND=$OPTIND || LONG_OPTION=$(echo $OPTARG | cut -d'=' -f1)
        [[ $LONG_OPTIND -ne -1 ]] && eval LONG_OPTARG="\$$LONG_OPTIND"
        OPTION=${ARRAY_OPTS[$LONG_OPTION]}
        [[ "x$OPTION" = "x" ]] &&  OPTION="?" OPTARG="-$LONG_OPTION"

        if [[ $( echo "${SCRIPT_OPTS}" | grep -c "${OPTION}:" ) -eq 1 ]]; then
            if [[ "x${LONG_OPTARG}" = "x" ]] || [[ "${LONG_OPTARG}" = -* ]]; then 
                OPTION=":" OPTARG="-$LONG_OPTION"
            else
                OPTARG="$LONG_OPTARG";
                if [[ $LONG_OPTIND -ne -1 ]]; then
                    [[ $OPTIND -le $Optnum ]] && OPTIND=$(( $OPTIND+1 ))
                    shift $OPTIND
                    OPTIND=1
                fi
            fi
        fi
    fi

    #== options follow by another option instead of argument ==#
    if [[ "x${OPTION}" != "x:" ]] && [[ "x${OPTION}" != "x?" ]] && [[ "${OPTARG}" = -* ]]; then 
        OPTARG="$OPTION" OPTION=":"
    fi

    #== manage options ==#
    case "$OPTION" in
        f  ) foo=1 bar=0                    ;;
        b  ) foo=0 bar=1                    ;;
        B  ) barfoo=${OPTARG}               ;;
        F  ) foobar=1 && foobar_name=${OPTARG} ;;
        h ) usagefull && exit 0 ;;
        : ) echo "${SCRIPT_NAME}: -$OPTARG: option requires an argument" >&2 && usage >&2 && exit 99 ;;
        ? ) echo "${SCRIPT_NAME}: -$OPTARG: unknown option" >&2 && usage >&2 && exit 99 ;;
    esac
done
shift $((${OPTIND} - 1))

এখানে একটি পরীক্ষা:

# Short options test
$ ./foobar_any_getopts.sh -bF "Hello world" -B 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello world
files=file1 file2

# Long and short options test
$ ./foobar_any_getopts.sh --bar -F Hello --barfoo 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello
files=file1 file2

অন্যথায় সাম্প্রতিক কার্ন শেল ksh93 এ getoptsস্বাভাবিকভাবেই দীর্ঘ বিকল্পগুলি বিশ্লেষণ করতে এবং এমনকি একইভাবে একটি ম্যান পৃষ্ঠা প্রদর্শন করতে পারে। ( Http://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options দেখুন )


0

ম বিল্ট-ইন OS X এর (বাসদ) getopt দীর্ঘ অপশন অবলম্বন পাওয়া যায়নি, কিন্তু গনুহ সংস্করণ আছে: brew install gnu-getopt। তারপর, অনুরূপ কিছু: cp /usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt /usr/local/bin/gnu-getopt


0

EasyOptions সংক্ষিপ্ত এবং দীর্ঘ বিকল্পগুলি পরিচালনা করে:

## Options:
##   --verbose, -v   Verbose mode
##   --logfile=NAME  Log filename

source easyoptions || exit

if test -n "${verbose}"; then
    echo "log file: ${logfile}"
    echo "arguments: ${arguments[@]}"
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.