ব্যাশে কীভাবে ব্যবহার করতে হবে তার একটি উদাহরণ


345

আমি myscriptএইভাবে ফাইল কল করতে চাই :

$ ./myscript -s 45 -p any_string

অথবা

$ ./myscript -h  #should display help
$ ./myscript     #should display help

আমার প্রয়োজনীয়তাগুলি হ'ল:

  • getopt ইনপুট আর্গুমেন্ট পেতে এখানে
  • -sউপস্থিত থাকলে তা পরীক্ষা করুন , যদি ত্রুটি না ফেরায়
  • -s45 বা 90 এর পরে মানটি পরীক্ষা করে দেখুন
  • -pউপস্থিত আছে এবং পরে একটি ইনপুট স্ট্রিং আছে তা পরীক্ষা করুন
  • যদি ব্যবহারকারী প্রবেশ করে ./myscript -hবা ঠিক ./myscriptতখন সহায়তা প্রদর্শন করে

আমি এখন পর্যন্ত এই কোডটি চেষ্টা করেছি:

#!/bin/bash
while getopts "h:s:" arg; do
  case $arg in
    h)
      echo "usage" 
      ;;
    s)
      strength=$OPTARG
      echo $strength
      ;;
  esac
done

কিন্তু সেই কোডটি দিয়ে আমি ত্রুটিগুলি পাই। বাশ এবং এটি দিয়ে কীভাবে করবেন getopt?


2
বিকল্পগুলি alচ্ছিক বলে মনে করা হচ্ছে। আপনার দ্বারা নির্দিষ্ট করা মানের প্রয়োজন হলে -s, এটি একটি অবস্থানগত যুক্তি করুন: ./myscript 45 anystring
চিপনার

@chepner$./myscript -s 45 -p any_string
মোহাম্মদ

-pআসলেই যদি কোনও বিকল্প হয় তবে এটি ঠিক আছে (অর্থাত্ আপনার প্রোগ্রামটি উপস্থিত না থাকলে এগিয়ে যেতে পারে)। এই ক্ষেত্রে ./myscript 45 -p any_string,। (আমি মনে করি এটি getoptমিশ্র বিকল্পগুলি এবং অবস্থানগত আর্গুমেন্টগুলি পরিচালনা করতে পারে, যদিও bashবিল্ট-ইন কমান্ডের getoptsজন্য বিকল্পের পরে সমস্ত
অবস্থানিক

উত্তর:


513
#!/bin/bash

usage() { echo "Usage: $0 [-s <45|90>] [-p <string>]" 1>&2; exit 1; }

while getopts ":s:p:" o; do
    case "${o}" in
        s)
            s=${OPTARG}
            ((s == 45 || s == 90)) || usage
            ;;
        p)
            p=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

if [ -z "${s}" ] || [ -z "${p}" ]; then
    usage
fi

echo "s = ${s}"
echo "p = ${p}"

উদাহরণ রান:

$ ./myscript.sh
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -h
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 10 -p foo
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 45 -p foo
s = 45
p = foo

$ ./myscript.sh -s 90 -p bar
s = 90
p = bar

19
গিওপটস কলগুলিতে কেন একটি অগ্রণী কোলন রয়েছে? "এইচ" এর পরে কখন কোলন থাকে?
e40

7
করা উচিত usage()সত্যিই 1 ফিরে?
পিথিকোস

6
পিথিকোস সাধারণ জ্ঞান আমাকে বলে যে -hএটির মাধ্যমে যখন আহ্বান করা হবে তখন ফিরে আসা উচিত 0, অস্তিত্বহীন পতাকাটি আঘাত করার পরে এটি ফিরে আসতে হবে >0(সরলতার জন্য আমি এই মামলার মধ্যে পার্থক্য করি নি এবং কেউ আপনাকে পরবর্তী ক্ষেত্রে ব্যবহারের পাঠ্য মুদ্রণ করতে বাধ্য করে না) । আমি এমন সব প্রোগ্রাম দেখেছি যা সবসময় ফিরে আসে != 0, এমনকি এখনও -h/--help। লোকেরা এটিকে বয়লারপ্লেট হিসাবে ব্যবহার করার ক্ষেত্রে আমার স্নিপেটটি আপডেট করা উচিত (আমি আশা করি না)?
অ্যাড্রিয়ান ফ্রাওয়ার্থিথ

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

4
@ user1011471 আপনি সঠিক! কোঁকড়া ধনুর্বন্ধনী, সুতরাং কথা বলতে, কেবল bashভেরিয়েবলগুলি সনাক্ত করতে লেক্সারকে সহায়তা করুন । এগুলি অনেক ক্ষেত্রে অপ্রয়োজনীয় এবং আমি সর্বদা সেগুলি ব্যবহার করি তা ব্যক্তিগত কোডিং শৈলীর বিষয়। আমার কাছে অস্পষ্টতার বিষয়ে পার্সিং বিধিগুলি মনে রাখার পরিবর্তে কেবল সর্বদা সেগুলি ব্যবহার করা সহজ (এবং সুন্দর)। সিটি-স্টাইলের ভাষায় (নান্দনিকতা এবং / অথবা মূর্খ ভুলগুলি এড়ানো) এর if (foo) { bar; }পরিবর্তে কেউ কেন লিখবে তা খুব সুন্দর if (foo) bar;
অ্যাড্রিয়ান ফ্রহ্বর্থম

109

মূল কোডটিতে সমস্যাটি হ'ল:

  • h:যেখানে প্যারামিটারটি হওয়া উচিত নয় তা প্রত্যাশা করে, সুতরাং এটি কেবল h(কোলন ছাড়াই) পরিবর্তন করুন
  • আশা করার জন্য -p any_string, আপনাকে p:যুক্তি তালিকায় যুক্ত করতে হবে

মূলত :বিকল্পটির পরে এর অর্থ যুক্তিটি দরকার।


এর মূল বাক্য গঠন getopts(দেখুন man bash:):

getopts OPTSTRING VARNAME [ARGS...]

কোথায়:

  • OPTSTRING প্রত্যাশিত যুক্তিগুলির তালিকা সহ স্ট্রিং করছে,

    • h- পরামিতি -h ছাড়াই বিকল্পের জন্য চেক করুন ; অসমর্থিত বিকল্পগুলিতে ত্রুটি দেয়;
    • h:- পরামিতি -h সহ বিকল্পের জন্য চেক করুন ; অসমর্থিত বিকল্পগুলিতে ত্রুটি দেয়;
    • abc- বিকল্পের জন্য চেক -a, -b, -c; অসমর্থিত বিকল্পগুলিতে ত্রুটি দেয় ;
    • :abc- বিকল্পের জন্য চেক -a, -b, -c; নীরব অসমর্থিত বিকল্পগুলি ত্রুটি;

      নোটস: অন্য কথায়, বিকল্পগুলির সামনে কোলন আপনাকে আপনার কোডের ত্রুটিগুলি পরিচালনা করতে দেয়। ভেরিয়েবলটি ?অসমর্থিত বিকল্পের :ক্ষেত্রে, মূল্য হারার ক্ষেত্রে ধারণ করবে ।

  • OPTARG - বর্তমান আর্গুমেন্ট মান সেট করা হয়,

  • OPTERR - বাশের ত্রুটি বার্তা প্রদর্শন করা উচিত কিনা তা নির্দেশ করে।

সুতরাং কোডটি হতে পারে:

#!/usr/bin/env bash
usage() { echo "$0 usage:" && grep " .)\ #" $0; exit 0; }
[ $# -eq 0 ] && usage
while getopts ":hs:p:" arg; do
  case $arg in
    p) # Specify p value.
      echo "p is ${OPTARG}"
      ;;
    s) # Specify strength, either 45 or 90.
      strength=${OPTARG}
      [ $strength -eq 45 -o $strength -eq 90 ] \
        && echo "Strength is $strength." \
        || echo "Strength needs to be either 45 or 90, $strength found instead."
      ;;
    h | *) # Display help.
      usage
      exit 0
      ;;
  esac
done

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

$ ./foo.sh 
./foo.sh usage:
    p) # Specify p value.
    s) # Specify strength, either 45 or 90.
    h | *) # Display help.
$ ./foo.sh -s 123 -p any_string
Strength needs to be either 45 or 90, 123 found instead.
p is any_string
$ ./foo.sh -s 90 -p any_string
Strength is 90.
p is any_string

দেখুন: বাশ হ্যাকার্স উইকিতে ছোট গোটপটস টিউটোরিয়াল


2
এই এ ব্যবহার ফাংশন পরিবর্তন করুন: usage() { echo "$0 usage:" && grep "[[:space:]].)\ #" $0 | sed 's/#//' | sed -r 's/([a-z])\)/-\1/'; exit 0; }। অক্ষর অপশনের আগে এটি কেবল একটি সাদা স্থানের অক্ষরের জন্য অ্যাকাউন্ট করে, মন্তব্য থেকে # টি সরিয়ে দেয় এবং অক্ষরের বিকল্পটি কমান্ডের জন্য পরিষ্কার করার আগে একটি '-' প্রিপেন্ড করে।
poageter

2
@ টেনারব: বিকল্পগুলির সামনে কোলন অসমর্থিত বিকল্পগুলিকে অগ্রাহ্য করে না তবে বাশ থেকে ত্রুটিগুলি শান্ত করে এবং আপনাকে এটি আপনার কোডে পরিচালনা করতে দেয়। চলকটিতে থাকবে '?' অসমর্থিত বিকল্পের ক্ষেত্রে এবং ':' মান অনুপস্থিতির ক্ষেত্রে।
হায়েনেক-পিচি- ভ্যাচোডিল

1
বিস্তারিত ডক্সের জন্য ধন্যবাদ, :আমি এই নোটগুলি না পাওয়া পর্যন্ত সঠিক পেতে সক্ষম হয়েছি না । আমাদের :সেই বিকল্পগুলিতে একটি যুক্ত করতে হবে যেখানে আমরা যুক্তির প্রত্যাশা করি।
আউখন

51

ব্যবহার getopt

কেন?

বিভ্রান্তি এড়াতে এবং আমরা যে বিকল্পগুলি পার্স করছি তা স্পষ্ট করার জন্য বিস্তৃত কমান্ড-লাইন যুক্তিগুলি পার্স করা যাতে কমান্ডের পাঠক বুঝতে পারে যে কী ঘটছে।

গোটপট কী?

getoptশেল পদ্ধতি দ্বারা সহজে পার্সিংয়ের জন্য কমান্ড লাইনে বিকল্পগুলি ব্রেক (পার্স) করতে এবং আইনী বিকল্পগুলি পরীক্ষা করার জন্য ব্যবহৃত হয়। এটি করার জন্য এটি জিএনইউ getopt(3)রুটিনগুলি ব্যবহার করে ।

getopt নিম্নলিখিত ধরণের বিকল্প থাকতে পারে।

  1. কোন মান বিকল্প
  2. কী-মান জোড় বিকল্প

দ্রষ্টব্য: এই নথিতে সিনট্যাক্স ব্যাখ্যা করার সময়:

  • [] এর ভিতরে যা কিছু আছে তা সিনট্যাক্স / উদাহরণগুলিতে optionচ্ছিক প্যারামিটার।
  • একটি স্থানধারক, যার অর্থ এটি একটি আসল মান দিয়ে প্রতিস্থাপন করা উচিত।

কিভাবে ব্যবহার করবেন getopt?

সিনট্যাক্স: প্রথম ফর্ম

getopt optstring parameters

উদাহরণ:

# This is correct
getopt "hv:t::" "-v 123 -t123"  
getopt "hv:t::" "-v123 -t123"  # -v and 123 doesn't have whitespace

# -h takes no value.
getopt "hv:t::" "-h -v123"


# This is wrong. after -t can't have whitespace.
# Only optional params cannot have whitespace between key and value
getopt "hv:t::" "-v 123 -t 123"

# Multiple arguments that takes value.
getopt "h:v:t::g::" "-h abc -v 123 -t21"

# Multiple arguments without value
# All of these are correct
getopt "hvt" "-htv"
getopt "hvt" "-h -t -v"
getopt "hvt" "-tv -h"

এখানে h, v, t টি বিকল্প রয়েছে এবং -h -v -t হল কমান্ড-লাইনে কীভাবে অপশন দেওয়া উচিত।

  1. 'এইচ' একটি মূল্যমানের বিকল্প।
  2. 'v:' ইঙ্গিত দেয় যে বিকল্প -v এর মান রয়েছে এবং এটি একটি বাধ্যতামূলক বিকল্প। ':' অর্থের একটি মান আছে।
  3. 't ::' ইঙ্গিত দেয় যে বিকল্প-টির মান রয়েছে তবে এটি alচ্ছিক। '::' অর্থ alচ্ছিক।

.চ্ছিক প্যারামে, মানটির সাথে বিকল্পের সাথে সাদা স্থান পৃথকীকরণ থাকতে পারে না। সুতরাং, "-t123" উদাহরণে, -t বিকল্প 123 এর মান।

সিনট্যাক্স: দ্বিতীয় ফর্ম

getopt [getopt_options] [--] [optstring] [parameters]

এখানে গোটোপ্টের পরে পাঁচটি ভাগে বিভক্ত হয়

  • কমান্ড নিজেই অর্থাৎ getopt
  • Getopt_options, এটি আর্গুমেন্টগুলি পার্স করার পদ্ধতি বর্ণনা করে। একক ড্যাশ দীর্ঘ বিকল্প, ডাবল ড্যাশ বিকল্প।
  • -, আপনি পার্স করতে চান এমন বিকল্পগুলি এবং অনুমোদিত সংক্ষিপ্ত বিকল্পগুলি থেকে getopt_options পৃথক করে
  • সংক্ষিপ্ত বিকল্পগুলি, অবিলম্বে নেওয়া হয় - পাওয়া যায়। ঠিক প্রথম সিনট্যাক্স ফর্ম মত।
  • পরামিতিগুলি, এগুলি হ'ল বিকল্পগুলি যা আপনি প্রোগ্রামটিতে প্রবেশ করেছেন। আপনি যে বিকল্পগুলি পার্স করতে চান এবং সেগুলিতে আসল মান সেট করে পেতে চান।

উদাহরণ

getopt -l "name:,version::,verbose" -- "n:v::V" "--name=Karthik -version=5.2 -verbose"

সিনট্যাক্স: তৃতীয় ফর্ম

getopt [getopt_options] [-o options] [--] [optstring] [parameters]

এখানে গোটোপ্টের পরে পাঁচটি ভাগে বিভক্ত হয়

  • কমান্ড নিজেই অর্থাৎ getopt
  • Getopt_options, এটি আর্গুমেন্টগুলি পার্স করার পদ্ধতি বর্ণনা করে। একক ড্যাশ দীর্ঘ বিকল্প, ডাবল ড্যাশ বিকল্প।
  • সংক্ষিপ্ত বিকল্পগুলি যেমন -o বা --options। ঠিক প্রথম সিনট্যাক্সের মতো তবে "-o" বিকল্পের সাথে এবং "-" এর আগে (ডাবল ড্যাশ)।
  • -, আপনি পার্স করতে চান এমন বিকল্পগুলি এবং অনুমোদিত সংক্ষিপ্ত বিকল্পগুলি থেকে getopt_options পৃথক করে
  • পরামিতিগুলি, এগুলি হ'ল বিকল্পগুলি যা আপনি প্রোগ্রামটিতে প্রবেশ করেছেন। আপনি যে বিকল্পগুলি পার্স করতে চান এবং সেগুলিতে আসল মান সেট করে পেতে চান।

উদাহরণ

getopt -l "name:,version::,verbose" -a -o "n:v::V" -- "-name=Karthik -version=5.2 -verbose"

GETOPT_OPTIONS

getopt_options কমান্ড-লাইন প্যারামগুলি পার্স করার পদ্ধতি পরিবর্তন করে।

নীচে কিছু getopt_options রয়েছে

বিকল্প: -l বা - দীর্ঘমেয়াদী

মানে getopt কমান্ডের দ্বারা বহু-চরিত্রের বিকল্পগুলি স্বীকৃত হওয়া উচিত। একাধিক বিকল্প কমা দ্বারা পৃথক করা হয়।

উদাহরণস্বরূপ, --name=Karthikকমান্ড লাইনে প্রেরণ করা একটি দীর্ঘ বিকল্প। Getopt এ, দীর্ঘ বিকল্পগুলির ব্যবহারের মতো like

getopt "name:,version" "--name=Karthik"

যেহেতু নাম: নির্দিষ্ট করা আছে, অপশনটিতে একটি মান থাকতে হবে

বিকল্প: -এ বা - বিকল্প

মানে getopt কমান্ডটি দীর্ঘ বিকল্পটিকে ডাবল ড্যাশ '-' এর পরিবর্তে একক ড্যাশ '-' দেওয়ার অনুমতি দেবে।

উদাহরণস্বরূপ, পরিবর্তে --name=Karthikআপনি কেবল ব্যবহার করতে পারেন-name=Karthik

getopt "name:,version" "-name=Karthik"

কোড সহ একটি সম্পূর্ণ স্ক্রিপ্ট উদাহরণ:

#!/bin/bash

# filename: commandLine.sh
# author: @theBuzzyCoder

showHelp() {
# `cat << EOF` This means that cat should stop reading when EOF is detected
cat << EOF  
Usage: ./installer -v <espo-version> [-hrV]
Install Pre-requisites for EspoCRM with docker in Development mode

-h, -help,          --help                  Display help

-v, -espo-version,  --espo-version          Set and Download specific version of EspoCRM

-r, -rebuild,       --rebuild               Rebuild php vendor directory using composer and compiled css using grunt

-V, -verbose,       --verbose               Run script in verbose mode. Will print out each step of execution.

EOF
# EOF is found above and hence cat command stops reading. This is equivalent to echo but much neater when printing out.
}


export version=0
export verbose=0
export rebuilt=0

# $@ is all command line parameters passed to the script.
# -o is for short options like -v
# -l is for long options with double dash like --version
# the comma separates different long options
# -a is for long options with single dash like -version
options=$(getopt -l "help,version:,verbose,rebuild,dryrun" -o "hv:Vrd" -a -- "$@")

# set --:
# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters 
# are set to the arguments, even if some of them begin with a ‘-’.
eval set -- "$options"

while true
do
case $1 in
-h|--help) 
    showHelp
    exit 0
    ;;
-v|--version) 
    shift
    export version=$1
    ;;
-V|--verbose)
    export verbose=1
    set -xv  # Set xtrace and verbose mode.
    ;;
-r|--rebuild)
    export rebuild=1
    ;;
--)
    shift
    break;;
esac
shift
done

এই স্ক্রিপ্ট ফাইলটি চালানো হচ্ছে:

# With short options grouped together and long option
# With double dash '--version'

bash commandLine.sh --version=1.0 -rV
# With short options grouped together and long option
# With single dash '-version'

bash commandLine.sh -version=1.0 -rV

# OR with short option that takes value, value separated by whitespace
# by key

bash commandLine.sh -v 1.0 -rV

# OR with short option that takes value, value without whitespace
# separation from key.

bash commandLine.sh -v1.0 -rV

# OR Separating individual short options

bash commandLine.sh -v1.0 -r -V


getopt getopts বনাম .. ভিন্ন ক্রস প্ল্যাটফর্ম সম্মতি
shadowbq

35

প্যাকেজযুক্ত উদাহরণটি getopt(আমার ডিস্ট্রো এটি এতে লাগিয়েছে /usr/share/getopt/getopt-parse.bash) দেখে মনে হচ্ছে এটি আপনার সমস্ত কেসকে কভার করে:

#!/bin/bash

# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh

# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument `more'
# Option b, argument ` very long '
# Remaining arguments:
# --> `par1'
# --> `another arg'
# --> `wow!*\?'

# Note that we use `"$@"' to let each command-line parameter expand to a 
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
     -n 'example.bash' -- "$@"`

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

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

while true ; do
    case "$1" in
        -a|--a-long) echo "Option a" ; shift ;;
        -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
        -c|--c-long) 
            # c has an optional argument. As we are in quoted mode,
            # an empty parameter will be generated if its optional
            # argument is not found.
            case "$2" in
                "") echo "Option c, no argument"; shift 2 ;;
                *)  echo "Option c, argument \`$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done

11
বহিরাগত কমান্ড getopt (1), ব্যবহার করা কখনোই নিরাপদ যদি না আপনি জানেন এটা গনুহ getopt হয়, তাহলে আপনি এটি একটি গনুহ-নির্দিষ্ট ভাবে কল, এবং আপনি তা নিশ্চিত GETOPT_COMPATIBLE পরিবেশে নয়। পরিবর্তে getopts (শেল বিল্টিন) ব্যবহার করুন, বা কেবল অবস্থানগত পরামিতিগুলির উপর লুপ করুন।
গিলস কুইনট

@ স্পটনিক, টিভিএম, এটি জানত না।
ব্রায়ান কেইন

14
হ্যাঁ, কোনও বাহ্যিক কমান্ড সেই মান দ্বারা নিরাপদ নয়। গিওপটসে অন্তর্নির্মিত গুরুত্বপূর্ণ বৈশিষ্ট্যগুলি অনুপস্থিত এবং আপনি যদি GETOPT_COMPATIBLE যাচাইয়ের বৈশিষ্ট্যগুলি পোর্টিংয়ের চেয়ে সহজ for
মাইকেল টেরি

12

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

আপডেট উত্তর:

ফাইলটি সংরক্ষণ করুন getopt.sh:

#!/bin/bash

function get_variable_name_for_option {
    local OPT_DESC=${1}
    local OPTION=${2}
    local VAR=$(echo ${OPT_DESC} | sed -e "s/.*\[\?-${OPTION} \([A-Z_]\+\).*/\1/g" -e "s/.*\[\?-\(${OPTION}\).*/\1FLAG/g")

    if [[ "${VAR}" == "${1}" ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

function parse_options {
    local OPT_DESC=${1}
    local INPUT=$(get_input_for_getopts "${OPT_DESC}")

    shift
    while getopts ${INPUT} OPTION ${@};
    do
        [ ${OPTION} == "?" ] && usage
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
            [ "${VARNAME}" != "" ] && eval "${VARNAME}=${OPTARG:-true}" # && printf "\t%s\n" "* Declaring ${VARNAME}=${!VARNAME} -- OPTIONS='$OPTION'"
    done

    check_for_required "${OPT_DESC}"

}

function check_for_required {
    local OPT_DESC=${1}
    local REQUIRED=$(get_required "${OPT_DESC}" | sed -e "s/\://g")
    while test -n "${REQUIRED}"; do
        OPTION=${REQUIRED:0:1}
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
                [ -z "${!VARNAME}" ] && printf "ERROR: %s\n" "Option -${OPTION} must been set." && usage
        REQUIRED=${REQUIRED:1}
    done
}

function get_input_for_getopts {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_optional {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/[^[]*\(\[[^]]*\]\)[^[]*/\1/g" -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_required {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/\[[^[]*\]//g" -e "s/[][ -]//g"
}

function usage {
    printf "Usage:\n\t%s\n" "${0} ${OPT_DESC}"
    exit 10
}

তারপরে আপনি এটি ব্যবহার করতে পারেন:

#!/bin/bash
#
# [ and ] defines optional arguments
#

# location to getopts.sh file
source ./getopt.sh
USAGE="-u USER -d DATABASE -p PASS -s SID [ -a START_DATE_TIME ]"
parse_options "${USAGE}" ${@}

echo ${USER}
echo ${START_DATE_TIME}

পুরানো উত্তর:

আমার সম্প্রতি একটি জেনেরিক পদ্ধতির ব্যবহার করা দরকার। আমি এই সমাধানটি পেরিয়ে এসেছি:

#!/bin/bash
# Option Description:
# -------------------
#
# Option description is based on getopts bash builtin. The description adds a variable name feature to be used
# on future checks for required or optional values.
# The option description adds "=>VARIABLE_NAME" string. Variable name should be UPPERCASE. Valid characters
# are [A-Z_]*.
#
# A option description example:
#   OPT_DESC="a:=>A_VARIABLE|b:=>B_VARIABLE|c=>C_VARIABLE"
#
# -a option will require a value (the colon means that) and should be saved in variable A_VARIABLE.
# "|" is used to separate options description.
# -b option rule applies the same as -a.
# -c option doesn't require a value (the colon absense means that) and its existence should be set in C_VARIABLE
#
#   ~$ echo get_options ${OPT_DESC}
#   a:b:c
#   ~$
#


# Required options 
REQUIRED_DESC="a:=>REQ_A_VAR_VALUE|B:=>REQ_B_VAR_VALUE|c=>REQ_C_VAR_FLAG"

# Optional options (duh)
OPTIONAL_DESC="P:=>OPT_P_VAR_VALUE|r=>OPT_R_VAR_FLAG"

function usage {
    IFS="|"
    printf "%s" ${0}
    for i in ${REQUIRED_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
    printf " %s" "-${i:0:1} $VARNAME"
    done

    for i in ${OPTIONAL_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
        printf " %s" "[-${i:0:1} $VARNAME]"
    done
    printf "\n"
    unset IFS
    exit
}

# Auxiliary function that returns options characters to be passed
# into 'getopts' from a option description.
# Arguments:
#   $1: The options description (SEE TOP)
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   OPTIONS=$(get_options ${OPT_DESC})
#   echo "${OPTIONS}"
#
# Output:
#   "h:f:PW"
function get_options {
    echo ${1} | sed -e "s/\([a-zA-Z]\:\?\)=>[A-Z_]*|\?/\1/g"
}

# Auxiliary function that returns all variable names separated by '|'
# Arguments:
#       $1: The options description (SEE TOP)
#
# Example:
#       OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#       VARNAMES=$(get_values ${OPT_DESC})
#       echo "${VARNAMES}"
#
# Output:
#       "H_VAR|F_VAR|P_VAR|W_VAR"
function get_variables {
    echo ${1} | sed -e "s/[a-zA-Z]\:\?=>\([^|]*\)/\1/g"
}

# Auxiliary function that returns the variable name based on the
# option passed by.
# Arguments:
#   $1: The options description (SEE TOP)
#   $2: The option which the variable name wants to be retrieved
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   H_VAR=$(get_variable_name ${OPT_DESC} "h")
#   echo "${H_VAR}"
#
# Output:
#   "H_VAR"
function get_variable_name {
    VAR=$(echo ${1} | sed -e "s/.*${2}\:\?=>\([^|]*\).*/\1/g")
    if [[ ${VAR} == ${1} ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

# Gets the required options from the required description
REQUIRED=$(get_options ${REQUIRED_DESC})

# Gets the optional options (duh) from the optional description
OPTIONAL=$(get_options ${OPTIONAL_DESC})

# or... $(get_options "${OPTIONAL_DESC}|${REQUIRED_DESC}")

# The colon at starts instructs getopts to remain silent
while getopts ":${REQUIRED}${OPTIONAL}" OPTION
do
    [[ ${OPTION} == ":" ]] && usage
    VAR=$(get_variable_name "${REQUIRED_DESC}|${OPTIONAL_DESC}" ${OPTION})
    [[ -n ${VAR} ]] && eval "$VAR=${OPTARG}"
done

shift $(($OPTIND - 1))

# Checks for required options. Report an error and exits if
# required options are missing.

# Using function version ...
VARS=$(get_variables ${REQUIRED_DESC})
IFS="|"
for VARNAME in $VARS;
do
    [[ -v ${VARNAME} ]] || usage
done
unset IFS

# ... or using IFS Version (no function)
OLDIFS=${IFS}
IFS="|"
for i in ${REQUIRED_DESC};
do
    VARNAME=$(echo $i | sed -e "s/.*=>//g")
    [[ -v ${VARNAME} ]] || usage
    printf "%s %s %s\n" "-${i:0:1}" "${!VARNAME:=present}" "${VARNAME}"
done
IFS=${OLDIFS}

আমি এটি মোটামুটি পরীক্ষা করিনি, তাই আমার সেখানে কিছু বাগ থাকতে পারে।


1
আপনি যদি getoptsকোনও ফাংশনে ব্যবহার করছেন তবে local OPTIND OPTARGফাংশনে যুক্ত করুন
গ্লেন জ্যাকম্যান

@glennjackman আসলে এটি ব্যবহারের চেয়ে আরও বেশি চালিত পদ্ধতির মতোgetopts
সেবাস্তিয়ান

8

পসিক্স 7 উদাহরণ

এটি আদর্শ থেকে উদাহরণটি যাচাইয়ের জন্যও মূল্যবান: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)   printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

এবং তারপরে আমরা এটি ব্যবহার করে দেখতে পারি:

$ sh a.sh
Remaining arguments are: 
$ sh a.sh -a
Option -a specified
Remaining arguments are: 
$ sh a.sh -b
No arg for -b option
Usage: a.sh: [-a] [-b value] args
$ sh a.sh -b myval
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh -a -b myval
Option -a specified
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh remain
Remaining arguments are: remain
$ sh a.sh -- -a remain
Remaining arguments are: -a remain

উবুন্টু 17.10 এ পরীক্ষিত, shড্যাশ হয় 0.5.8।


0

"গোটোপস" এবং "গোটোপ্ট" খুব সীমাবদ্ধ। "Getopt" এটিকে মোটেও ব্যবহার না করার পরামর্শ দেওয়া হলেও এটি দীর্ঘ বিকল্প দেয়। যেখানে "getopts" কেবলমাত্র "-a" "-b" এর মতো একক অক্ষরের বিকল্পগুলিকে অনুমতি দেয়। যে কোনও একটি ব্যবহার করার সময় আরও কয়েকটি অসুবিধা রয়েছে।

সুতরাং আমি একটি ছোট স্ক্রিপ্ট লিখেছি যা "গোটপটস" এবং "গোটোপ্ট" প্রতিস্থাপন করে। এটি একটি শুরু, এটি সম্ভবত অনেক উন্নতি হতে পারে।

আপডেট 08-04-2020 : আমি হাইফেনের জন্য সমর্থন যোগ করেছি যেমন "--প্যাকেজ-নাম"।

ব্যবহার: "./script.sh প্যাকেজ ইনস্টল - প্যাকেজ" স্থান সহ নাম "- বিল্ড - আর্কাইভ"

# Example:
# parseArguments "${@}"
# echo "${ARG_0}" -> package
# echo "${ARG_1}" -> install
# echo "${ARG_PACKAGE}" -> "name with space"
# echo "${ARG_BUILD}" -> 1 (true)
# echo "${ARG_ARCHIVE}" -> 1 (true)
function parseArguments() {
  PREVIOUS_ITEM=''
  COUNT=0
  for CURRENT_ITEM in "${@}"
  do
    if [[ ${CURRENT_ITEM} == "--"* ]]; then
      printf -v "ARG_$(formatArgument "${CURRENT_ITEM}")" "%s" "1" # could set this to empty string and check with [ -z "${ARG_ITEM-x}" ] if it's set, but empty.
    else
      if [[ $PREVIOUS_ITEM == "--"* ]]; then
        printf -v "ARG_$(formatArgument "${PREVIOUS_ITEM}")" "%s" "${CURRENT_ITEM}"
      else
        printf -v "ARG_${COUNT}" "%s" "${CURRENT_ITEM}"
      fi
    fi

    PREVIOUS_ITEM="${CURRENT_ITEM}"
    (( COUNT++ ))
  done
}

# Format argument.
function formatArgument() {
  ARGUMENT="${1^^}" # Capitalize.
  ARGUMENT="${ARGUMENT/--/}" # Remove "--".
  ARGUMENT="${ARGUMENT//-/_}" # Replace "-" with "_".
  echo "${ARGUMENT}"
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.