আমি কীভাবে কমান্ড লাইন যুক্তিতে পার্স করব?


1917

বলুন, আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা এই লাইনের সাথে ডেকে আনে:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

বা এই এক:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 

প্রতিটি ক্ষেত্রে এই যেমন যে পার্স গৃহীত উপায় (বা দুই কিছু সমন্বয়) কী $v, $fএবং $dসব সেট করা হবে trueএবং $outFileসমান হবে /fizz/someOtherFile?


1
: Zsh-ব্যবহারকারীদের জন্য একটি মহান builtin নামক zparseopts যা করতে পারি zparseopts -D -E -M -- d=debug -debug=dআর উভয় আছে -dএবং --debug$debugঅ্যারে echo $+debug[1]0 বা 1 ফিরে আসবে যদি ঐ এক ব্যবহার করা হয়। রেফ: zsh.org/mla/users/2011/msg00350.html
dezza

1
সত্যিই ভাল টিউটোরিয়াল: linuxcommand.org/lc3_wss0120.php । আমি বিশেষত "কমান্ড লাইন বিকল্প" উদাহরণ পছন্দ করি।
গ্যাব্রিয়েল স্ট্যাপলস

উত্তর:


2671

পদ্ধতি # 1: getopt [গুলি] ছাড়াই ব্যাশ ব্যবহার করা

কী-মান-জুটি যুক্তিগুলি পাস করার দুটি সাধারণ উপায় হ'ল:

স্পেস-বিভাজক স্থান (যেমন, --option argument) (গোটপট [গুলি] ছাড়াই)

ব্যবহার demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts

cat >/tmp/demo-space-separated.sh <<'EOF'
#!/bin/bash

POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -e|--extension)
    EXTENSION="$2"
    shift # past argument
    shift # past value
    ;;
    -s|--searchpath)
    SEARCHPATH="$2"
    shift # past argument
    shift # past value
    ;;
    -l|--lib)
    LIBPATH="$2"
    shift # past argument
    shift # past value
    ;;
    --default)
    DEFAULT=YES
    shift # past argument
    ;;
    *)    # unknown option
    POSITIONAL+=("$1") # save it in an array for later
    shift # past argument
    ;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "LIBRARY PATH    = ${LIBPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 "$1"
fi
EOF

chmod +x /tmp/demo-space-separated.sh

/tmp/demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts

উপরের ব্লকটি কপি-পেস্ট করা থেকে আউটপুট:

FILE EXTENSION  = conf
SEARCH PATH     = /etc
LIBRARY PATH    = /usr/lib
DEFAULT         =
Number files in SEARCH PATH with EXTENSION: 14
Last line of file specified as non-opt/last argument:
#93.184.216.34    example.com

সমান সমান-পৃথক (উদাহরণস্বরূপ --option=argument) (getopt [গুলি] ছাড়াই)

ব্যবহার demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts

cat >/tmp/demo-equals-separated.sh <<'EOF'
#!/bin/bash

for i in "$@"
do
case $i in
    -e=*|--extension=*)
    EXTENSION="${i#*=}"
    shift # past argument=value
    ;;
    -s=*|--searchpath=*)
    SEARCHPATH="${i#*=}"
    shift # past argument=value
    ;;
    -l=*|--lib=*)
    LIBPATH="${i#*=}"
    shift # past argument=value
    ;;
    --default)
    DEFAULT=YES
    shift # past argument with no value
    ;;
    *)
          # unknown option
    ;;
esac
done
echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "LIBRARY PATH    = ${LIBPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 $1
fi
EOF

chmod +x /tmp/demo-equals-separated.sh

/tmp/demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts

উপরের ব্লকটি কপি-পেস্ট করা থেকে আউটপুট:

FILE EXTENSION  = conf
SEARCH PATH     = /etc
LIBRARY PATH    = /usr/lib
DEFAULT         =
Number files in SEARCH PATH with EXTENSION: 14
Last line of file specified as non-opt/last argument:
#93.184.216.34    example.com

ভালভাবে বুঝতে ${i#*=}মধ্যে "অপসারণ সাবস্ট্রিং" এর জন্য অনুসন্ধান এই সহায়িকার । এটি `sed 's/[^=]*=//' <<< "$i"`কার্যত সমতুল্য যা একটি অহেতুক সাবপ্রসেসকে `echo "$i" | sed 's/[^=]*=//'`কল করে বা যা দুটি অযৌক্তিক সাবপ্রসেসিকে কল করে ।

পদ্ধতি # 2: getopt [গুলি] দিয়ে ব্যাশ ব্যবহার করা

থেকে: http://mywiki.wooledge.org/BashFAQ/035#getopts

getopt (1) সীমাবদ্ধতা (পুরানো, তুলনামূলক-সাম্প্রতিক getoptসংস্করণ):

  • খালি স্ট্রিংগুলি যুক্তিগুলি পরিচালনা করতে পারে না
  • এম্বেড শ্বেত স্পেস দিয়ে যুক্তিগুলি পরিচালনা করতে পারে না

আরও সাম্প্রতিক getoptসংস্করণগুলিতে এই সীমাবদ্ধতা নেই।

অতিরিক্তভাবে, পসিএক্স শেল (এবং অন্যান্য) অফার করে getoptsযার মধ্যে এই সীমাবদ্ধতা নেই। আমি একটি সরল getoptsউদাহরণ অন্তর্ভুক্ত করেছি ।

ব্যবহার demo-getopts.sh -vf /etc/hosts foo bar

cat >/tmp/demo-getopts.sh <<'EOF'
#!/bin/sh

# A POSIX variable
OPTIND=1         # Reset in case getopts has been used previously in the shell.

# Initialize our own variables:
output_file=""
verbose=0

while getopts "h?vf:" opt; do
    case "$opt" in
    h|\?)
        show_help
        exit 0
        ;;
    v)  verbose=1
        ;;
    f)  output_file=$OPTARG
        ;;
    esac
done

shift $((OPTIND-1))

[ "${1:-}" = "--" ] && shift

echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"
EOF

chmod +x /tmp/demo-getopts.sh

/tmp/demo-getopts.sh -vf /etc/hosts foo bar

উপরের ব্লকটি কপি-পেস্ট করা থেকে আউটপুট:

verbose=1, output_file='/etc/hosts', Leftovers: foo bar

এর সুবিধাগুলি হ'ল getopts:

  1. এটি আরও বহনযোগ্য, এবং অন্যান্য শেলগুলিতে কাজ করবে dash
  2. এটি -vf filenameস্বয়ংক্রিয়ভাবে সাধারণত ইউনিক্স উপায়ে একাধিক একক বিকল্পগুলি পরিচালনা করতে পারে ।

এর অসুবিধাটি getoptsহ'ল এটি অতিরিক্ত কোড ছাড়াই সংক্ষিপ্ত বিকল্পগুলি ( -h, না --help) পরিচালনা করতে পারে ।

একটি গিওপটস টিউটোরিয়াল রয়েছে যা ব্যাখ্যা করে যে সমস্ত সিনট্যাক্স এবং ভেরিয়েবলগুলি কী বোঝায়। ব্যাশে, রয়েছে help getopts, যা তথ্যপূর্ণ হতে পারে।


44
এটা কি সত্যি? উইকিপিডিয়া অনুসারে একটি নতুন জিএনইউ বর্ধিত সংস্করণ রয়েছে getoptযার এর সমস্ত কার্যকারিতা getoptsএবং তারপরে কিছু রয়েছে। man getoptউবুন্টুতে 13.04 getopt - parse command options (enhanced)নাম হিসাবে ফলাফল আউটপুট , তাই আমি ধারণা করি এই বর্ধিত সংস্করণটি এখন মানসম্মত।
লিভভেন

47
আপনার সিস্টেমে কিছু একটা নির্দিষ্ট উপায় হ'ল "স্ট্যান্ডার্ড হচ্ছে" এর অনুমানের ভিত্তিটি খুব দুর্বল।
szablica

13
@ লাইভভেন, এটি getoptজিএনইউ ইউটিলিটি নয়, এটির একটি অংশ util-linux
স্টিফেন চেজেলাস

4
আপনি ব্যবহার করেন তাহলে -gt 0, আপনার অপসারণ shiftপর esac, সমস্ত বৃদ্ধি shift1 এবং এই ক্ষেত্রে যোগ করুন: *) break;;আপনি অ optionnal আর্গুমেন্ট সব ব্যবস্থা করতে সক্ষম। উদাহরণস্বরূপ: পেস্টবিন.com
নিকোলাস লাকোম্ব

2
আপনি প্রতিধ্বনিত করবেন না –default। প্রথম উদাহরণে, আমি লক্ষ্য করেছি যে যদি –defaultশেষ যুক্তি হয় তবে এটি প্রসেস করা হয় না (যদি না while [[ $# -gt 1 ]]while [[ $# -gt 0 ]]
অপশন

562

কোনও উত্তর বর্ধিত getopt উল্লেখ । এবং শীর্ষ ভোটের উত্তরটি বিভ্রান্তিমূলক: এটি -⁠vfdস্টাইলের সংক্ষিপ্ত বিকল্পগুলি (ওপি দ্বারা অনুরোধ করা) বা অবস্থানগত আর্গুমেন্টের পরে বিকল্পগুলি (ওপি দ্বারা অনুরোধও করা হয়েছে) উপেক্ষা করে ; এবং এটি পার্সিং-ত্রুটি উপেক্ষা করে। পরিবর্তে:

  • getoptইউজার-লিনাক্স বা পূর্বে জিএনইউ গ্লিবসি থেকে বর্ধিত ব্যবহার করুন1
  • এটি getopt_long()GNU glibc এর সি ফাংশন নিয়ে কাজ করে।
  • রয়েছে সব দরকারী বৈশিষ্ট্য (অন্যদের তাদের না থাকে):
    • 2 টি আর্গুমেন্টে অক্ষর এবং এমনকি বাইনারি উদ্ধৃত করে স্পেসগুলি পরিচালনা করে (অ বর্ধিত এটি এটি getoptকরতে পারে না)
    • এটি শেষে বিকল্পগুলি পরিচালনা করতে পারে: script.sh -o outFile file1 file2 -v(এটি getoptsকরবেন না)
    • পারবেন =-style দীর্ঘ বিকল্প: script.sh --outfile=fileOut --infile fileIn(উভয় যার ফলে যদি স্ব পার্সিং লম্বা হয়)
    • সংযুক্ত সংক্ষিপ্ত বিকল্পগুলির অনুমতি দেয়, উদাহরণস্বরূপ -vfd(স্ব-পার্সিং হলে আসল কাজ)
    • স্পর্শ অপশন-আর্গুমেন্ট, যেমন -oOutfileবা-vfdoOutfile
  • ইতিমধ্যে 3 বছরের পুরানো যে কোনও জিএনইউ সিস্টেম এটি মিস করছে না (যেমন কোনও লিনাক্স এটি রয়েছে)।
  • আপনি এর অস্তিত্বের জন্য এটি পরীক্ষা করতে পারেন: getopt --test→ ফেরতের মান 4।
  • অন্যান্য getoptবা শেল-বিল্টিন getoptsসীমিত ব্যবহারের।

নিম্নলিখিত কল

myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
myscript -v -f -d -o/fizz/someOtherFile -- ./foo/bar/someFile
myscript --verbose --force --debug ./foo/bar/someFile -o/fizz/someOtherFile
myscript --output=/fizz/someOtherFile ./foo/bar/someFile -vfd
myscript ./foo/bar/someFile -df -v --output /fizz/someOtherFile

সব ফিরে

verbose: y, force: y, debug: y, in: ./foo/bar/someFile, out: /fizz/someOtherFile

নিম্নলিখিত সঙ্গে myscript

#!/bin/bash
# saner programming env: these switches turn some bugs into errors
set -o errexit -o pipefail -o noclobber -o nounset

# -allow a command to fail with !’s side effect on errexit
# -use return value from ${PIPESTATUS[0]}, because ! hosed $?
! getopt --test > /dev/null 
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
    echo 'I’m sorry, `getopt --test` failed in this environment.'
    exit 1
fi

OPTIONS=dfo:v
LONGOPTS=debug,force,output:,verbose

# -regarding ! and PIPESTATUS see above
# -temporarily store output to be able to check for errors
# -activate quoting/enhanced mode (e.g. by writing out “--options”)
# -pass arguments only via   -- "$@"   to separate them correctly
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
    # e.g. return value is 1
    #  then getopt has complained about wrong arguments to stdout
    exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"

d=n f=n v=n outFile=-
# now enjoy the options in order and nicely split until we see --
while true; do
    case "$1" in
        -d|--debug)
            d=y
            shift
            ;;
        -f|--force)
            f=y
            shift
            ;;
        -v|--verbose)
            v=y
            shift
            ;;
        -o|--output)
            outFile="$2"
            shift 2
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "Programming error"
            exit 3
            ;;
    esac
done

# handle non-option arguments
if [[ $# -ne 1 ]]; then
    echo "$0: A single input file is required."
    exit 4
fi

echo "verbose: $v, force: $f, debug: $d, in: $1, out: $outFile"

সাইগউইন সহ বেশিরভাগ "বাশ-সিস্টেমগুলি" তে 1 বর্ধিত গোটপট পাওয়া যায়; OS X এর চেষ্টা GNU-getopt ইনস্টল চোলাই বাsudo port install getopt
2 POSIXexec()নিয়মাবলী কমান্ড লাইন আর্গুমেন্ট মধ্যে বাইনারি শূন্য পাস কোন নির্ভরযোগ্য উপায় আছে; এই বাইটগুলি অকাল যুক্তিতে1997 এর বা তার আগে প্রকাশিত
3 টি প্রথম সংস্করণ যুক্ত করেছিল (আমি কেবল এটি 1997 সালে ফিরে এসেছি)


4
এর জন্য ধন্যবাদ. এন.ইউইউইকিপিডিয়া.আর / উইকি / গেটপ্টসের বৈশিষ্ট্য সারণী থেকে সুনির্দিষ্টভাবে নিশ্চিত করা হয়েছে , যদি আপনার দীর্ঘ বিকল্পের জন্য সমর্থন প্রয়োজন হয় এবং আপনি সোলারিসে নেই, getoptতবে যাবার উপায়।
জনসিপ

4
আমি বিশ্বাস করি যে এর সাথে একমাত্র সতর্কতামূলক getoptবিষয়টি হ'ল এটি র‍্যাপার স্ক্রিপ্টগুলিতে সুবিধাজনকভাবে ব্যবহার করা যাবে না যেখানে কারও কাছে মোড়কের স্ক্রিপ্টের সাথে নির্দিষ্ট কয়েকটি বিকল্প থাকতে পারে এবং তারপরে নন-র্যাপার-স্ক্রিপ্ট বিকল্পগুলি মোড়ানো কার্যকর, অক্ষত act ধরা যাক আমার কাছে একটি grepমোড়ক কল আছে mygrepএবং আমার কাছে একটি বিকল্প --fooনির্দিষ্ট আছে mygrep, তবে আমি করতে পারি না mygrep --foo -A 2এবং -A 2স্বয়ংক্রিয়ভাবে পাস হয়ে গেলাম grep; আমি প্রয়োজন করতে mygrep --foo -- -A 2আপনার সমাধানের শীর্ষে আমার বাস্তবায়ন এখানে ।
দক্ষ মোদী

2
@ ববপল ইউজ-লিনাক্স সম্পর্কে আপনার বক্তব্যটি ভুল এবং বিভ্রান্তিকর: প্যাকেজটি উবুন্টু / ডেবিয়ানকে "প্রয়োজনীয়" হিসাবে চিহ্নিত করা হয়েছে। যেমন, এটি সর্বদা ইনস্টল করা থাকে। - আপনি কোন ডিস্ট্রোসের কথা বলছেন (যেখানে আপনি বলছেন যে এটি প্রয়োজনে ইনস্টল করা প্রয়োজন)?
রবার্ট সিমার

3
নোট করুন এটি ম্যাকে কমপক্ষে বর্তমান 10.14.3 পর্যন্ত কাজ করে না। জাহাজটি যে জাহাজটি হয় তা বিএসডি গিওপট ১৯৯৯ ...
jjj

2
@ ট্রান্সং বুলিয়ান প্রত্যাবর্তন মূল্যের অবহেলা। এবং এর পার্শ্ব প্রতিক্রিয়া: একটি কমান্ডকে ব্যর্থ হওয়ার অনুমতি দিন (অন্যথায় ত্রুটিযুক্তভাবে প্রোগ্রামটি বাতিল করতে হবে)। - স্ক্রিপ্টের মন্তব্যগুলি আপনাকে আরও বলে। অন্যথায়:man bash
রবার্ট সিমার

144

আরও সুসংহত উপায়

script.sh

#!/bin/bash

while [[ "$#" -gt 0 ]]; do
    case $1 in
        -d|--deploy) deploy="$2"; shift ;;
        -u|--uglify) uglify=1 ;;
        *) echo "Unknown parameter passed: $1"; exit 1 ;;
    esac
    shift
done

echo "Should deploy? $deploy"
echo "Should uglify? $uglify"

ব্যবহার:

./script.sh -d dev -u

# OR:

./script.sh --deploy dev --uglify

3
আমি এই কি করছি। আছে while [[ "$#" > 1 ]]যদি আমি একটি বুলিয়ান ফ্ল্যাগে সঙ্গে সঙ্গতিপূর্ণ বিভক্তি সমর্থন করতে চান ./script.sh --debug dev --uglify fast --verbose। উদাহরণ: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58
hfossli

12
কি দারুন! সহজ এবং পরিষ্কার! এইভাবেই আমি এটি ব্যবহার করছি: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58
hfossli

2
উত্সের সাথে কথা বলার চেয়ে বা আপনার কার্যকারিতাটি আসলে কোথায় শুরু হয় তা নিয়ে মানুষ আশ্চর্য হওয়ার চেয়ে প্রতিটি স্ক্রিপ্টে আটকানো অনেকটাই সুন্দর।
রিয়েলহ্যান্ডি

সতর্কতা: এটি সদৃশ যুক্তি সহ্য করে, সর্বশেষতম যুক্তিটি বিরাজ করে। যেমন ./script.sh -d dev -d prodফলাফল হবে deploy == 'prod'। আমি যাইহোক এটি ব্যবহার করেছি: পি :): +1:
ইয়ার

আমি এটি ব্যবহার করছি (ধন্যবাদ!) তবে মনে রাখবেন যে এটি খালি যুক্তির মানকে মঞ্জুরি দেয়, যেমন ./script.sh -dকোনও ত্রুটি তৈরি করে না তবে কেবল $deployএকটি খালি স্ট্রিংয়ে সেট করে।
EM0

137

থেকে: ডিজিটালপিয়ার ডট কম অপরিশোধিত পরিবর্তনগুলি

ব্যবহার myscript.sh -p=my_prefix -s=dirname -l=libname

#!/bin/bash
for i in "$@"
do
case $i in
    -p=*|--prefix=*)
    PREFIX="${i#*=}"

    ;;
    -s=*|--searchpath=*)
    SEARCHPATH="${i#*=}"
    ;;
    -l=*|--lib=*)
    DIR="${i#*=}"
    ;;
    --default)
    DEFAULT=YES
    ;;
    *)
            # unknown option
    ;;
esac
done
echo PREFIX = ${PREFIX}
echo SEARCH PATH = ${SEARCHPATH}
echo DIRS = ${DIR}
echo DEFAULT = ${DEFAULT}

ভালভাবে বুঝতে ${i#*=}মধ্যে "অপসারণ সাবস্ট্রিং" এর জন্য অনুসন্ধান এই সহায়িকার । এটি `sed 's/[^=]*=//' <<< "$i"`কার্যত সমতুল্য যা একটি অহেতুক সাবপ্রসেসকে `echo "$i" | sed 's/[^=]*=//'`কল করে বা যা দুটি অযৌক্তিক সাবপ্রসেসিকে কল করে ।


4
ঝরঝরে! যদিও এটি স্থান-বিচ্ছিন্ন আর্গুমেন্টের জন্য কাজ করবে না mount -t tempfs ...। একজন সম্ভবত ভালো কিছু মাধ্যমে এই ঠিক করতে পারবো while [ $# -ge 1 ]; do param=$1; shift; case $param in; -p) prefix=$1; shift;;ইত্যাদি
Tobias Kienzler

3
এটি -vfdশৈলীর সংযুক্ত সংক্ষিপ্ত বিকল্পগুলি পরিচালনা করতে পারে না ।
রবার্ট সিমার

105

getopt()/ getopts()একটি ভাল বিকল্প। এখান থেকে চুরি :

এই মিনি স্ক্রিপ্টে "getopt" এর সহজ ব্যবহার দেখানো হয়েছে:

#!/bin/bash
echo "Before getopt"
for i
do
  echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
  echo "-->$i"
done

আমরা যা বলেছি তা হ'ল -a, -b, -c বা -d- এর যে কোনও একটিকেই অনুমতি দেওয়া হবে তবে সেই-সি এর পরে একটি যুক্তি ("গ:" বলে যে) অনুসরণ করা হয়।

যদি আমরা এটিকে "জি" বলি এবং এটি ব্যবহার করে দেখি:

bash-2.05a$ ./g -abc foo
Before getopt
-abc
foo
After getopt
-->-a
-->-b
-->-c
-->foo
-->--

আমরা দুটি আর্গুমেন্ট দিয়ে শুরু করি এবং "getopt" বিকল্পগুলি বিচ্ছিন্ন করে এবং প্রতিটিকে তার নিজস্ব যুক্তিতে রাখি। এটি "-" যুক্ত করেছে।


4
ব্যবহার $*হ'ল ভাঙা ব্যবহার getopt। (এটি স্পেস সহ আর্গুমেন্টকে হোসি করে)) সঠিক ব্যবহারের জন্য আমার উত্তর দেখুন ।
রবার্ট সিমার

আপনি কেন এটিকে আরও জটিল করে তুলতে চান?
এসডসোলার

@ ম্যাট জে, স্ক্রিপ্টের প্রথম অংশ (i এর জন্য) আপনি ফাঁকা জায়গায় আর্গুমেন্টগুলি হ্যান্ডেল করতে সক্ষম হবেন যদি আপনি $ i এর পরিবর্তে "$ i" ব্যবহার করেন। গিওপটগুলি শূন্যস্থান দিয়ে তর্কগুলি পরিচালনা করতে সক্ষম বলে মনে হচ্ছে না। আই লুপের জন্য গোটপট ব্যবহার করে কী সুবিধা হবে?
thebunnyrules

99

এড়াতে অন্য উদাহরণ যুক্ত করার ঝুঁকিতে, এখানে আমার স্কিম scheme

  • হ্যান্ডলগুলি -n argএবং--name=arg
  • শেষে যুক্তি দেয় allows
  • কিছু ভুল বানান থাকলে বুদ্ধিমান ত্রুটিগুলি দেখায়
  • সামঞ্জস্যপূর্ণ, বাশিজম ব্যবহার করে না
  • পঠনযোগ্য, একটি লুপে রাষ্ট্র বজায় রাখা প্রয়োজন হয় না

আশা করি এটি কারও কাজে লাগবে।

while [ "$#" -gt 0 ]; do
  case "$1" in
    -n) name="$2"; shift 2;;
    -p) pidfile="$2"; shift 2;;
    -l) logfile="$2"; shift 2;;

    --name=*) name="${1#*=}"; shift 1;;
    --pidfile=*) pidfile="${1#*=}"; shift 1;;
    --logfile=*) logfile="${1#*=}"; shift 1;;
    --name|--pidfile|--logfile) echo "$1 requires an argument" >&2; exit 1;;

    -*) echo "unknown option: $1" >&2; exit 1;;
    *) handle_argument "$1"; shift 1;;
  esac
done

4
দেরি করার জন্য দুঃখিত. আমার স্ক্রিপ্টে, হ্যান্ডেল_গারগমেন্ট ফাংশনটি সমস্ত অ-বিকল্প যুক্তি গ্রহণ করে। আপনি যে লাইনটি চান তা দিয়ে এই লাইনটি প্রতিস্থাপন করতে পারেন, *) die "unrecognized argument: $1"বা একটি ভেরিয়েবলের মধ্যে আরগগুলি সংগ্রহ করতে পারেন *) args+="$1"; shift 1;;
ব্রোনসন

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

2
সুন্দর সংযোগ কোড, তবে -n এবং অন্য কোনও আরগ ব্যবহারের কারণে ত্রুটির কারণে অনন্ত লুপের কারণ হয় না shift 2, shiftপরিবর্তে দু'বার পরিবর্তে জারি করা হয় shift 2। সম্পাদনার পরামর্শ দেওয়া হয়েছে।
লকসাস

42

এই প্রশ্নটি সম্পর্কে আমি প্রায় 4 বছর দেরীতে আছি তবে ফিরে দিতে চাই। আমি আমার পুরানো অ্যাডহক প্যারাম পার্সিং পরিষ্কার করার জন্য পূর্ববর্তী উত্তরগুলিকে প্রাথমিক পয়েন্ট হিসাবে ব্যবহার করেছি। আমি নীচের টেমপ্লেট কোডটি রিফ্যাক্ট করেছিলাম। এটি দীর্ঘ বা সংক্ষিপ্ত উভয় প্যারামগুলি পরিচালনা করে = বা স্পেস দ্বারা পৃথক যুক্তিগুলির পাশাপাশি একসাথে একাধিক শর্ট প্যারামকে গোষ্ঠীযুক্ত করে। অবশেষে এটি কোনও নন-প্যারাম যুক্তি আবার $ 1, $ 2 .. ভেরিয়েবলগুলিতে সন্নিবেশ করায়। আমি আশা করি এটি কার্যকর

#!/usr/bin/env bash

# NOTICE: Uncomment if your script depends on bashisms.
#if [ -z "$BASH_VERSION" ]; then bash $0 $@ ; exit $? ; fi

echo "Before"
for i ; do echo - $i ; done


# Code template for parsing command line parameters using only portable shell
# code, while handling both long and short params, handling '-f file' and
# '-f=file' style param data and also capturing non-parameters to be inserted
# back into the shell positional parameters.

while [ -n "$1" ]; do
        # Copy so we can modify it (can't modify $1)
        OPT="$1"
        # Detect argument termination
        if [ x"$OPT" = x"--" ]; then
                shift
                for OPT ; do
                        REMAINS="$REMAINS \"$OPT\""
                done
                break
        fi
        # Parse current opt
        while [ x"$OPT" != x"-" ] ; do
                case "$OPT" in
                        # Handle --flag=value opts like this
                        -c=* | --config=* )
                                CONFIGFILE="${OPT#*=}"
                                shift
                                ;;
                        # and --flag value opts like this
                        -c* | --config )
                                CONFIGFILE="$2"
                                shift
                                ;;
                        -f* | --force )
                                FORCE=true
                                ;;
                        -r* | --retry )
                                RETRY=true
                                ;;
                        # Anything unknown is recorded for later
                        * )
                                REMAINS="$REMAINS \"$OPT\""
                                break
                                ;;
                esac
                # Check for multiple short options
                # NOTICE: be sure to update this pattern to match valid options
                NEXTOPT="${OPT#-[cfr]}" # try removing single short opt
                if [ x"$OPT" != x"$NEXTOPT" ] ; then
                        OPT="-$NEXTOPT"  # multiple short opts, keep going
                else
                        break  # long form, exit inner loop
                fi
        done
        # Done with that param. move to next
        shift
done
# Set the non-parameters back into the positional parameters ($1 $2 ..)
eval set -- $REMAINS


echo -e "After: \n configfile='$CONFIGFILE' \n force='$FORCE' \n retry='$RETRY' \n remains='$REMAINS'"
for i ; do echo - $i ; done

এই কোড ভালো আর্গুমেন্ট সহ অপশন হ্যান্ডেল করতে পারে না: -c1। এবং =তাদের যুক্তি থেকে সংক্ষিপ্ত বিকল্পগুলি পৃথক করার ব্যবহার অস্বাভাবিক ...
রবার্ট সিমার

2
কোডের এই দরকারী অংশ নিয়ে আমি দুটি সমস্যার মধ্যে পড়েছিলাম: ১) "-c = foo" এর ক্ষেত্রে "শিফট" পরবর্তী প্যারামিটারটি খাওয়া শেষ করে; এবং 2) 'সি' সংযুক্তযোগ্য সংক্ষিপ্ত বিকল্পগুলির জন্য "[সিএফআর]" ধরণে অন্তর্ভুক্ত করা উচিত নয়।
sfnd

36

আমি স্ক্রিপ্টগুলিতে পোর্টেবল পার্সিং লিখতে এত হতাশ হয়েছি যে আমি আরগবাশ লিখেছি - এটি একটি FOSS কোড জেনারেটর যা আপনার স্ক্রিপ্টের জন্য আর্গুমেন্ট-পার্সিং কোড উত্পন্ন করতে পারে এবং এতে কিছু দুর্দান্ত বৈশিষ্ট্য রয়েছে:

https://argbash.io


আরগবাশ লেখার জন্য ধন্যবাদ, আমি কেবল এটি ব্যবহার করেছি এবং এটি ভালভাবে কাজ করতে পেরেছি। আমি বেশিরভাগ আরগবাশের জন্য গিয়েছিলাম কারণ এটি ওএস এক্স 10.11 এল ক্যাপিটেনে পাওয়া পুরানো বাশ 3.x সমর্থনকারী একটি কোড জেনারেটর। একমাত্র ক্ষতিটি হ'ল কোড জেনারেটর পদ্ধতির অর্থ আপনার মুল স্ক্রিপ্টে মডিউলকে কল করার তুলনায় প্রচুর কোড।
রিচভেল

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

জানা ভাল. এই উদাহরণটি আকর্ষণীয় তবে এখনও সত্য নয় - সম্ভবত আপনি উত্পন্ন স্ক্রিপ্টের নামটি 'পার্স_লিবি.এস' বা এটির মতো করে রাখতে পারেন এবং মূল স্ক্রিপ্টটি যেখানে কল করেন তা দেখাতে পারেন (মোড়কের স্ক্রিপ্ট বিভাগে যা আরও জটিল ব্যবহারের ক্ষেত্রে)।
রিচভেল

আরগবাশের সাম্প্রতিক সংস্করণে এই বিষয়গুলি সম্বোধন করা হয়েছিল: ডকুমেন্টেশনটি উন্নত করা হয়েছে, একটি কুইকস্টার্ট আরগবাশ-ইআরএন স্ক্রিপ্ট চালু করা হয়েছে এবং আপনি অনলাইনে আরগবাশ.ও
জেনারেটে

29

আমার উত্তর মূলত ব্রুনো ব্রোনোস্কির উত্তরের উপর ভিত্তি করে , তবে আমি তার দুটি খাঁটি বাশ প্রয়োগ বাস্তবায়িত করেছি যা আমি প্রায়শই ঘন ঘন ব্যবহার করি।

# As long as there is at least one more argument, keep looping
while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
        # This is a flag type option. Will catch either -f or --foo
        -f|--foo)
        FOO=1
        ;;
        # Also a flag type option. Will catch either -b or --bar
        -b|--bar)
        BAR=1
        ;;
        # This is an arg value type option. Will catch -o value or --output-file value
        -o|--output-file)
        shift # past the key and to the value
        OUTPUTFILE="$1"
        ;;
        # This is an arg=value type option. Will catch -o=value or --output-file=value
        -o=*|--output-file=*)
        # No need to shift here since the value is part of the same string
        OUTPUTFILE="${key#*=}"
        ;;
        *)
        # Do whatever you want with extra options
        echo "Unknown option '$key'"
        ;;
    esac
    # Shift after checking all the cases to get the next option
    shift
done

এটি আপনাকে উভয় স্থান পৃথক বিকল্প / মান, পাশাপাশি সমান সংজ্ঞায়িত মান রাখতে দেয়।

সুতরাং আপনি আপনার স্ক্রিপ্টটি ব্যবহার করে চালাতে পারেন:

./myscript --foo -b -o /fizz/file.txt

পাশাপাশি:

./myscript -f --bar -o=/fizz/file.txt

এবং উভয়ের একই পরিণতি হওয়া উচিত।

পেশাদাররা:

  • উভয় -arg = মান এবং -র্গ মানের জন্য অনুমতি দেয়

  • আপনি ব্যাশে ব্যবহার করতে পারেন এমন কোনও আর্গ নেমের সাথে কাজ করে

    • অর্থ -এ বা-আরগ বা - আরগ বা-আরগ বা যাই হোক না কেন
  • খাঁটি বাশ গোটপট বা গিওপ্টস শিখতে / ব্যবহার করার দরকার নেই

কনস:

  • আরগগুলি একত্রিত করতে পারি না

    • মানে নো-বিসি। আপনাকে অবশ্যই -a -b -c করতে হবে

এগুলিই কেবলমাত্র আমার মাথার উপরের দিক থেকে ভাবতে পারে pros


15

আমি মনে করি এটি ব্যবহার করার পক্ষে এটি যথেষ্ট সহজ:

#!/bin/bash
#

readopt='getopts $opts opt;rc=$?;[ $rc$opt == 0? ]&&exit 1;[ $rc == 0 ]||{ shift $[OPTIND-1];false; }'

opts=vfdo:

# Enumerating options
while eval $readopt
do
    echo OPT:$opt ${OPTARG+OPTARG:$OPTARG}
done

# Enumerating arguments
for arg
do
    echo ARG:$arg
done

অনুরোধের উদাহরণ:

./myscript -v -do /fizz/someOtherFile -f ./foo/bar/someFile
OPT:v 
OPT:d 
OPT:o OPTARG:/fizz/someOtherFile
OPT:f 
ARG:./foo/bar/someFile

1
আমি সব পড়েছি এবং এটি আমার পছন্দসই। আমি -a=1আরগসি স্টাইল হিসাবে ব্যবহার করতে পছন্দ করি না । আমি প্রথম একক ব্যবধান সঙ্গে প্রধান বিকল্প -options এবং পরে বিশেষ বেশী লাগাতে পছন্দ করা -o option। আমি আরগভিগুলি পড়ার সবচেয়ে সহজ-বনাম-ভাল উপায় খুঁজছি।
এম 3 এন্ড

এটি সত্যিই ভালভাবে কাজ করছে তবে আপনি যদি কোনও অ-এর পক্ষে যুক্তিটি পাস করেন: বিকল্পটি নিম্নলিখিত সমস্ত বিকল্পকে আর্গুমেন্ট হিসাবে গ্রহণ করা হবে। আপনি ./myscript -v -d fail -o /fizz/someOtherFile -f ./foo/bar/someFileনিজের স্ক্রিপ্ট দিয়ে এই লাইনটি চেক করতে পারেন । -d বিকল্পটি ডি হিসাবে সেট করা নেই:
এম

15

@ গুনেইসাস দ্বারা দুর্দান্ত উত্তরের প্রসারিত করা, এখানে একটি টুইটক দেওয়া হয়েছে যা ব্যবহারকারীরা তাদের পছন্দসই বাক্য গঠন ব্যবহার করতে দেয়, যেমন

command -x=myfilename.ext --another_switch 

বনাম

command -x myfilename.ext --another_switch

এর অর্থ সমানটি সাদা স্থানের সাথে প্রতিস্থাপন করা যেতে পারে।

এই "অস্পষ্ট ব্যাখ্যা" আপনার পছন্দ অনুসারে নাও হতে পারে, তবে আপনি যদি অন্যান্য স্ক্রিপ্টগুলি বিনিময়যোগ্য স্ক্রিপ্টগুলি তৈরি করে থাকেন (যেমন আমার ক্ষেত্রে যেমন ffmpeg নিয়ে কাজ করা উচিত) তবে নমনীয়তা কার্যকর।

STD_IN=0

prefix=""
key=""
value=""
for keyValue in "$@"
do
  case "${prefix}${keyValue}" in
    -i=*|--input_filename=*)  key="-i";     value="${keyValue#*=}";; 
    -ss=*|--seek_from=*)      key="-ss";    value="${keyValue#*=}";;
    -t=*|--play_seconds=*)    key="-t";     value="${keyValue#*=}";;
    -|--stdin)                key="-";      value=1;;
    *)                                      value=$keyValue;;
  esac
  case $key in
    -i) MOVIE=$(resolveMovie "${value}");  prefix=""; key="";;
    -ss) SEEK_FROM="${value}";          prefix=""; key="";;
    -t)  PLAY_SECONDS="${value}";           prefix=""; key="";;
    -)   STD_IN=${value};                   prefix=""; key="";; 
    *)   prefix="${keyValue}=";;
  esac
done

13

নিচের উদাহরনের মাধ্যমে দেখানো কিভাবে ব্যবহার করতে getoptএবং evalএবং HEREDOCএবং shiftএবং একটি প্রয়োজনীয় মান অনুসরণ করে ছাড়া স্বল্প ও দীর্ঘ পরামিতি হ্যান্ডেল করতে। এছাড়াও স্যুইচ / কেস স্টেটমেন্টটি সংক্ষিপ্ত এবং অনুসরণ করা সহজ।

#!/usr/bin/env bash

# usage function
function usage()
{
   cat << HEREDOC

   Usage: $progname [--num NUM] [--time TIME_STR] [--verbose] [--dry-run]

   optional arguments:
     -h, --help           show this help message and exit
     -n, --num NUM        pass in a number
     -t, --time TIME_STR  pass in a time string
     -v, --verbose        increase the verbosity of the bash script
     --dry-run            do a dry run, dont change any files

HEREDOC
}  

# initialize variables
progname=$(basename $0)
verbose=0
dryrun=0
num_str=
time_str=

# use getopt and store the output into $OPTS
# note the use of -o for the short options, --long for the long name options
# and a : for any option that takes a parameter
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"

while true; do
  # uncomment the next line to see how shift is working
  # echo "\$1:\"$1\" \$2:\"$2\""
  case "$1" in
    -h | --help ) usage; exit; ;;
    -n | --num ) num_str="$2"; shift 2 ;;
    -t | --time ) time_str="$2"; shift 2 ;;
    --dry-run ) dryrun=1; shift ;;
    -v | --verbose ) verbose=$((verbose + 1)); shift ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

if (( $verbose > 0 )); then

   # print out all the parameters we read in
   cat <<-EOM
   num=$num_str
   time=$time_str
   verbose=$verbose
   dryrun=$dryrun
EOM
fi

# The rest of your script below

উপরের স্ক্রিপ্টের সর্বাধিক উল্লেখযোগ্য লাইনগুলি হ'ল:

OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; exit 1 ; fi
eval set -- "$OPTS"

while true; do
  case "$1" in
    -h | --help ) usage; exit; ;;
    -n | --num ) num_str="$2"; shift 2 ;;
    -t | --time ) time_str="$2"; shift 2 ;;
    --dry-run ) dryrun=1; shift ;;
    -v | --verbose ) verbose=$((verbose + 1)); shift ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

সংক্ষিপ্ত, বিন্দুতে, পঠনযোগ্য এবং হ্যান্ডেলগুলি প্রায় সমস্ত কিছু (আইএমএইচও)।

আশা করি যে কাউকে সাহায্য করবে।


1
এটি সেরা উত্তরগুলির মধ্যে একটি।
মিঃ পলিহর্ল

11

আমি আপনাকে ফাংশন দিচ্ছি parse_paramsযা কমান্ড লাইন থেকে প্যারামগুলি পার্স করবে।

  1. এটি একটি খাঁটি বাশ সমাধান, অতিরিক্ত কোনও সুবিধা নেই।
  2. বৈশ্বিক সুযোগ দূষিত করে না।
  3. ভেরিয়েবলগুলি ব্যবহার করার জন্য অনায়াসে আপনাকে সহজ ফেরত দেয়, যাতে আপনি আরও যুক্তি তৈরি করতে পারেন।
  4. প্যারামগুলির আগে ড্যাশগুলির পরিমাণ কোনও ব্যাপার নয় ( --allসমান -allসমান all=all)

নীচের স্ক্রিপ্টটি হ'ল একটি অনুলিপি-কার্যকারী প্রদর্শন। show_useকীভাবে ব্যবহার করবেন তা বুঝতে ফাংশন দেখুন parse_params

সীমাবদ্ধতা:

  1. স্থান সীমানাঙ্কিত প্যারামগুলি সমর্থন করে না ( -d 1)
  2. পরম নামগুলি ড্যাশগুলি হারাবে --any-paramএবং -anyparamসমান
  3. eval $(parse_params "$@")বাশ ফাংশনের অভ্যন্তরে অবশ্যই ব্যবহার করা উচিত (এটি বৈশ্বিক পরিসরে কাজ করবে না)

#!/bin/bash

# Universal Bash parameter parsing
# Parse equal sign separated params into named local variables
# Standalone named parameter value will equal its param name (--force creates variable $force=="force")
# Parses multi-valued named params into an array (--path=path1 --path=path2 creates ${path[*]} array)
# Puts un-named params as-is into ${ARGV[*]} array
# Additionally puts all named params as-is into ${ARGN[*]} array
# Additionally puts all standalone "option" params as-is into ${ARGO[*]} array
# @author Oleksii Chekulaiev
# @version v1.4.1 (Jul-27-2018)
parse_params ()
{
    local existing_named
    local ARGV=() # un-named params
    local ARGN=() # named params
    local ARGO=() # options (--params)
    echo "local ARGV=(); local ARGN=(); local ARGO=();"
    while [[ "$1" != "" ]]; do
        # Escape asterisk to prevent bash asterisk expansion, and quotes to prevent string breakage
        _escaped=${1/\*/\'\"*\"\'}
        _escaped=${_escaped//\'/\\\'}
        _escaped=${_escaped//\"/\\\"}
        # If equals delimited named parameter
        nonspace="[^[:space:]]"
        if [[ "$1" =~ ^${nonspace}${nonspace}*=..* ]]; then
            # Add to named parameters array
            echo "ARGN+=('$_escaped');"
            # key is part before first =
            local _key=$(echo "$1" | cut -d = -f 1)
            # Just add as non-named when key is empty or contains space
            if [[ "$_key" == "" || "$_key" =~ " " ]]; then
                echo "ARGV+=('$_escaped');"
                shift
                continue
            fi
            # val is everything after key and = (protect from param==value error)
            local _val="${1/$_key=}"
            # remove dashes from key name
            _key=${_key//\-}
            # skip when key is empty
            # search for existing parameter name
            if (echo "$existing_named" | grep "\b$_key\b" >/dev/null); then
                # if name already exists then it's a multi-value named parameter
                # re-declare it as an array if needed
                if ! (declare -p _key 2> /dev/null | grep -q 'declare \-a'); then
                    echo "$_key=(\"\$$_key\");"
                fi
                # append new value
                echo "$_key+=('$_val');"
            else
                # single-value named parameter
                echo "local $_key='$_val';"
                existing_named=" $_key"
            fi
        # If standalone named parameter
        elif [[ "$1" =~ ^\-${nonspace}+ ]]; then
            # remove dashes
            local _key=${1//\-}
            # Just add as non-named when key is empty or contains space
            if [[ "$_key" == "" || "$_key" =~ " " ]]; then
                echo "ARGV+=('$_escaped');"
                shift
                continue
            fi
            # Add to options array
            echo "ARGO+=('$_escaped');"
            echo "local $_key=\"$_key\";"
        # non-named parameter
        else
            # Escape asterisk to prevent bash asterisk expansion
            _escaped=${1/\*/\'\"*\"\'}
            echo "ARGV+=('$_escaped');"
        fi
        shift
    done
}

#--------------------------- DEMO OF THE USAGE -------------------------------

show_use ()
{
    eval $(parse_params "$@")
    # --
    echo "${ARGV[0]}" # print first unnamed param
    echo "${ARGV[1]}" # print second unnamed param
    echo "${ARGN[0]}" # print first named param
    echo "${ARG0[0]}" # print first option param (--force)
    echo "$anyparam"  # print --anyparam value
    echo "$k"         # print k=5 value
    echo "${multivalue[0]}" # print first value of multi-value
    echo "${multivalue[1]}" # print second value of multi-value
    [[ "$force" == "force" ]] && echo "\$force is set so let the force be with you"
}

show_use "param 1" --anyparam="my value" param2 k=5 --force --multi-value=test1 --multi-value=test2

আপনার ব্যাশ স্ক্রিপ্টে আসা show_use "$@"
প্যারামগুলি

মূলত আমি জানতে পেরেছি যে github.com/renatosilva/easyoptions একই পদ্ধতিতে একই কাজ করে তবে এই ফাংশনটির চেয়ে কিছুটা বেশি বিশাল।
ওলেকসেই চেকুলিয়েভ

10

EasyOptions কোনও পার্সিংয়ের প্রয়োজন নেই:

## Options:
##   --verbose, -v  Verbose mode
##   --output=FILE  Output filename

source easyoptions || exit

if test -n "${verbose}"; then
    echo "output file is ${output}"
    echo "${arguments[@]}"
fi

আমার উদাহরণটি বুঝতে আমার এক মিনিট সময় লেগেছিল যে আপনার উদাহরণের স্ক্রিপ্টের শীর্ষে দেওয়া মন্তব্যগুলি একটি ডিফল্ট ব্যবহারের সাহায্যের স্ট্রিং, পাশাপাশি যুক্তির বিশদ বিবরণ সরবরাহ করার জন্য পার্স করা হচ্ছে। এটি একটি উজ্জ্বল সমাধান এবং আমি দুঃখিত যে এটি 2 বছরে 6 টি ভোট পেয়েছিল। লোকেরা খেয়াল করার জন্য সম্ভবত এই প্রশ্নটি খুব জলাবদ্ধ।
রূপক

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

আমি একটি দ্রুত সংস্করণ চাই, সম্ভবত সি তে লেখা আছে, এছাড়াও এমন একটি সংস্করণ যা zsh এর সাথে সামঞ্জস্যপূর্ণ। হতে পারে এটি একটি পৃথক প্রশ্নের দাবি রাখে ("বাশ-এর ​​মতো শেলগুলিতে কমান্ড-লাইন যুক্তিগুলি পার্স করার কোনও উপায় আছে যা স্ট্যান্ডার্ড দীর্ঘ-বিকল্প সিনট্যাক্স গ্রহণ করে এবং বিকল্পের নামগুলি একাধিকবার টাইপ করার প্রয়োজন হয় না?")।
রূপান্তরিত

10

গিওপটস দুর্দান্ত কাজ করে যদি # 1 আপনার এটি ইনস্টল করা আছে এবং # 2 আপনি একই প্ল্যাটফর্মে এটি চালানোর পরিকল্পনা করছেন। ওএসএক্স এবং লিনাক্স (উদাহরণস্বরূপ) এই ক্ষেত্রে আলাদাভাবে আচরণ করে।

এখানে একটি (নন গিওপটস) সমাধান যা সমান, অ-সমান এবং বুলিয়ান পতাকা সমর্থন করে। উদাহরণস্বরূপ আপনি আপনার স্ক্রিপ্টটি এভাবে চালাতে পারেন:

./script --arg1=value1 --arg2 value2 --shouldClean

# parse the arguments.
COUNTER=0
ARGS=("$@")
while [ $COUNTER -lt $# ]
do
    arg=${ARGS[$COUNTER]}
    let COUNTER=COUNTER+1
    nextArg=${ARGS[$COUNTER]}

    if [[ $skipNext -eq 1 ]]; then
        echo "Skipping"
        skipNext=0
        continue
    fi

    argKey=""
    argVal=""
    if [[ "$arg" =~ ^\- ]]; then
        # if the format is: -key=value
        if [[ "$arg" =~ \= ]]; then
            argVal=$(echo "$arg" | cut -d'=' -f2)
            argKey=$(echo "$arg" | cut -d'=' -f1)
            skipNext=0

        # if the format is: -key value
        elif [[ ! "$nextArg" =~ ^\- ]]; then
            argKey="$arg"
            argVal="$nextArg"
            skipNext=1

        # if the format is: -key (a boolean flag)
        elif [[ "$nextArg" =~ ^\- ]] || [[ -z "$nextArg" ]]; then
            argKey="$arg"
            argVal=""
            skipNext=0
        fi
    # if the format has not flag, just a value.
    else
        argKey=""
        argVal="$arg"
        skipNext=0
    fi

    case "$argKey" in 
        --source-scmurl)
            SOURCE_URL="$argVal"
        ;;
        --dest-scmurl)
            DEST_URL="$argVal"
        ;;
        --version-num)
            VERSION_NUM="$argVal"
        ;;
        -c|--clean)
            CLEAN_BEFORE_START="1"
        ;;
        -h|--help|-help|--h)
            showUsage
            exit
        ;;
    esac
done

8

স্ট্যাকের উচ্চতর কোথাও একই সময়ে চালানো গিওপটগুলি এড়াতে আমি কোনও ফাংশনটিতে এটি করি:

function waitForWeb () {
   local OPTIND=1 OPTARG OPTION
   local host=localhost port=8080 proto=http
   while getopts "h:p:r:" OPTION; do
      case "$OPTION" in
      h)
         host="$OPTARG"
         ;;
      p)
         port="$OPTARG"
         ;;
      r)
         proto="$OPTARG"
         ;;
      esac
   done
...
}

8

@ ব্রুনো-ব্রোনোস্কির উত্তরটি প্রসারিত করে কিছু সাধারণ বিন্যাস পরিচালনা করতে আমি একটি "প্রিপ্রোসেসর" যুক্ত করেছি:

  • প্রসারিত --longopt=valহয়--longopt val
  • প্রসারিত -xyzহয়-x -y -z
  • --পতাকাগুলির সমাপ্তি নির্দেশ করার জন্য সমর্থন করে
  • অপ্রত্যাশিত বিকল্পগুলির জন্য একটি ত্রুটি দেখায়
  • কমপ্যাক্ট এবং সহজেই পঠনযোগ্য অপশনগুলি স্যুইচ করুন
#!/bin/bash

# Report usage
usage() {
  echo "Usage:"
  echo "$(basename $0) [options] [--] [file1, ...]"

  # Optionally exit with a status code
  if [ -n "$1" ]; then
    exit "$1"
  fi
}

invalid() {
  echo "ERROR: Unrecognized argument: $1" >&2
  usage 1
}

# Pre-process options to:
# - expand -xyz into -x -y -z
# - expand --longopt=arg into --longopt arg
ARGV=()
END_OF_OPT=
while [[ $# -gt 0 ]]; do
  arg="$1"; shift
  case "${END_OF_OPT}${arg}" in
    --) ARGV+=("$arg"); END_OF_OPT=1 ;;
    --*=*)ARGV+=("${arg%%=*}" "${arg#*=}") ;;
    --*) ARGV+=("$arg"); END_OF_OPT=1 ;;
    -*) for i in $(seq 2 ${#arg}); do ARGV+=("-${arg:i-1:1}"); done ;;
    *) ARGV+=("$arg") ;;
  esac
done

# Apply pre-processed options
set -- "${ARGV[@]}"

# Parse options
END_OF_OPT=
POSITIONAL=()
while [[ $# -gt 0 ]]; do
  case "${END_OF_OPT}${1}" in
    -h|--help)      usage 0 ;;
    -p|--password)  shift; PASSWORD="$1" ;;
    -u|--username)  shift; USERNAME="$1" ;;
    -n|--name)      shift; names+=("$1") ;;
    -q|--quiet)     QUIET=1 ;;
    -C|--copy)      COPY=1 ;;
    -N|--notify)    NOTIFY=1 ;;
    --stdin)        READ_STDIN=1 ;;
    --)             END_OF_OPT=1 ;;
    -*)             invalid "$1" ;;
    *)              POSITIONAL+=("$1") ;;
  esac
  shift
done

# Restore positional parameters
set -- "${POSITIONAL[@]}"

6

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

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

উদাহরণ: যে কোনও

# flag
-f
--foo

# option with required argument
-b"Hello World"
-b "Hello World"
--bar "Hello World"
--bar="Hello World"

# option with optional argument
--baz
--baz="Optional Hello"

#!/usr/bin/env bash

usage() {
  cat - >&2 <<EOF
NAME
    program-name.sh - Brief description

SYNOPSIS
    program-name.sh [-h|--help]
    program-name.sh [-f|--foo]
                    [-b|--bar <arg>]
                    [--baz[=<arg>]]
                    [--]
                    FILE ...

REQUIRED ARGUMENTS
  FILE ...
          input files

OPTIONS
  -h, --help
          Prints this and exits

  -f, --foo
          A flag option

  -b, --bar <arg>
          Option requiring an argument <arg>

  --baz[=<arg>]
          Option that has an optional argument <arg>. If <arg>
          is not specified, defaults to 'DEFAULT'
  --     
          Specify end of options; useful if the first non option
          argument starts with a hyphen

EOF
}

fatal() {
    for i; do
        echo -e "${i}" >&2
    done
    exit 1
}

# For long option processing
next_arg() {
    if [[ $OPTARG == *=* ]]; then
        # for cases like '--opt=arg'
        OPTARG="${OPTARG#*=}"
    else
        # for cases like '--opt arg'
        OPTARG="${args[$OPTIND]}"
        OPTIND=$((OPTIND + 1))
    fi
}

# ':' means preceding option character expects one argument, except
# first ':' which make getopts run in silent mode. We handle errors with
# wildcard case catch. Long options are considered as the '-' character
optspec=":hfb:-:"
args=("" "$@")  # dummy first element so $1 and $args[1] are aligned
while getopts "$optspec" optchar; do
    case "$optchar" in
        h) usage; exit 0 ;;
        f) foo=1 ;;
        b) bar="$OPTARG" ;;
        -) # long option processing
            case "$OPTARG" in
                help)
                    usage; exit 0 ;;
                foo)
                    foo=1 ;;
                bar|bar=*) next_arg
                    bar="$OPTARG" ;;
                baz)
                    baz=DEFAULT ;;
                baz=*) next_arg
                    baz="$OPTARG" ;;
                -) break ;;
                *) fatal "Unknown option '--${OPTARG}'" "see '${0} --help' for usage" ;;
            esac
            ;;
        *) fatal "Unknown option: '-${OPTARG}'" "See '${0} --help' for usage" ;;
    esac
done

shift $((OPTIND-1))

if [ "$#" -eq 0 ]; then
    fatal "Expected at least one required argument FILE" \
    "See '${0} --help' for usage"
fi

echo "foo=$foo, bar=$bar, baz=$baz, files=${@}"

5

আমি আমার বিকল্পটি পার্সিংয়ের সংস্করণটি দিতে চাই, যা নিম্নলিখিতটির জন্য অনুমতি দেয়:

-s p1
--stage p1
-w somefolder
--workfolder somefolder
-sw p1 somefolder
-e=hello

এছাড়াও এটির জন্য অনুমতি দেয় (অযাচিত হতে পারে):

-s--workfolder p1 somefolder
-se=hello p1
-swe=hello p1 somefolder

কোনও বিকল্পে = ব্যবহার করতে হবে কিনা তা আপনাকে ব্যবহারের আগে সিদ্ধান্ত নিতে হবে। এটি কোডটি পরিষ্কার রাখা (ইশ)।

while [[ $# > 0 ]]
do
    key="$1"
    while [[ ${key+x} ]]
    do
        case $key in
            -s*|--stage)
                STAGE="$2"
                shift # option has parameter
                ;;
            -w*|--workfolder)
                workfolder="$2"
                shift # option has parameter
                ;;
            -e=*)
                EXAMPLE="${key#*=}"
                break # option has been fully handled
                ;;
            *)
                # unknown option
                echo Unknown option: $key #1>&2
                exit 10 # either this: my preferred way to handle unknown options
                break # or this: do this to signal the option has been handled (if exit isn't used)
                ;;
        esac
        # prepare for next option in this key, if any
        [[ "$key" = -? || "$key" == --* ]] && unset key || key="${key/#-?/-}"
    done
    shift # option(s) fully processed, proceed to next input argument
done

1
+ {কী + x on এ "+ x" এর অর্থ কী?
লুকা দাভানজো

1
'কী' উপস্থিত আছে কি নেই তা দেখার পরীক্ষা। আরও নীচে আমি কীটি আনসেট করি এবং এটি লুপ করার সময় অভ্যন্তরীণ অংশকে ভেঙে দেয়।
গ্যালামোক

5

সমাধান যা শত্রুহীন আর্গুমেন্ট সংরক্ষণ করে। ডেমোস অন্তর্ভুক্ত।

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

ব্যবহার হ'ল: ./myscript -flag flagvariable -otherflag flagvar2

আপনাকে যা করতে হবে তা হ'ল বৈধফলক লাইনটি সম্পাদন করতে হবে। এটি একটি হাইফেন প্রেন্ডস করে এবং সমস্ত যুক্তি সন্ধান করে। এটি এর পরে পরবর্তী যুক্তিটিকে পতাকা নাম হিসাবে হিসাবে সংজ্ঞায়িত করে

./myscript -flag flagvariable -otherflag flagvar2
echo $flag $otherflag
flagvariable flagvar2

প্রধান কোড (সংক্ষিপ্ত সংস্করণ, আরও নিচে উদাহরণ সহ ভার্বোজ, ত্রুটিযুক্ত একটি সংস্করণ):

#!/usr/bin/env bash
#shebang.io
validflags="rate time number"
count=1
for arg in $@
do
    match=0
    argval=$1
    for flag in $validflags
    do
        sflag="-"$flag
        if [ "$argval" == "$sflag" ]
        then
            declare $flag=$2
            match=1
        fi
    done
        if [ "$match" == "1" ]
    then
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done
#Cleanup then restore the leftovers
shift $#
set -- $leftovers

প্রতিধ্বনি সংস্করণটি প্রতিধ্বনিত ডেমোতে অন্তর্নিহিত সহ:

#!/usr/bin/env bash
#shebang.io
rate=30
time=30
number=30
echo "all args
$@"
validflags="rate time number"
count=1
for arg in $@
do
    match=0
    argval=$1
#   argval=$(echo $@ | cut -d ' ' -f$count)
    for flag in $validflags
    do
            sflag="-"$flag
        if [ "$argval" == "$sflag" ]
        then
            declare $flag=$2
            match=1
        fi
    done
        if [ "$match" == "1" ]
    then
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done

#Cleanup then restore the leftovers
echo "pre final clear args:
$@"
shift $#
echo "post final clear args:
$@"
set -- $leftovers
echo "all post set args:
$@"
echo arg1: $1 arg2: $2

echo leftovers: $leftovers
echo rate $rate time $time number $number

চূড়ান্ত এক, যদি একটি অবৈধ-বিভাগটি পাস করা হয় তবে এটির একটি ত্রুটিযুক্ত।

#!/usr/bin/env bash
#shebang.io
rate=30
time=30
number=30
validflags="rate time number"
count=1
for arg in $@
do
    argval=$1
    match=0
        if [ "${argval:0:1}" == "-" ]
    then
        for flag in $validflags
        do
                sflag="-"$flag
            if [ "$argval" == "$sflag" ]
            then
                declare $flag=$2
                match=1
            fi
        done
        if [ "$match" == "0" ]
        then
            echo "Bad argument: $argval"
            exit 1
        fi
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done
#Cleanup then restore the leftovers
shift $#
set -- $leftovers
echo rate $rate time $time number $number
echo leftovers: $leftovers

পেশাদাররা: এটি কী করে, এটি খুব ভালভাবে পরিচালনা করে। এটি অব্যবহৃত আর্গুমেন্টগুলি সংরক্ষণ করে যা এখানে অন্যান্য সমাধানগুলির মধ্যে অনেকগুলি না। এটি স্ক্রিপ্টে হাত দ্বারা সংজ্ঞায়িত না করে ভেরিয়েবলগুলি কল করার অনুমতি দেয়। যদি কোনও সম্পর্কিত যুক্তি না দেওয়া হয় তবে এটি ভেরিয়েবলগুলির প্রিপোপুলেশনকেও অনুমতি দেয়। (ভার্বোজের উদাহরণ দেখুন)।

কনস: একক জটিল আরগ স্ট্রিংকে পার্স করতে পারে না যেমন -xcvf একক যুক্তি হিসাবে প্রক্রিয়া করবে। আপনি কিছুটা সহজেই আমার কাছে অতিরিক্ত কোড লিখতে পারেন যা এই কার্যকারিতাটি যুক্ত করে।


5

আমি আমার প্রকল্পটি জমা দিতে চাই: https://github.com/flyingangel/argparser

source argparser.sh
parse_args "$@"

যে হিসাবে সহজ। আর্গুমেন্ট হিসাবে একই নামের সাথে পরিবেশটি ভেরিয়েবলের সাথে জনবহুল হয়ে উঠবে


3

দ্রষ্টব্য এটি getopt(1)এটিএন্ডটি থেকে একটি স্বল্প জীবন্ত ভুল ছিল।

getopt 1984 সালে তৈরি করা হয়েছিল তবে 1986 সালে ইতিমধ্যে তাকে সমাহিত করা হয়েছে কারণ এটি সত্যিকারের ব্যবহারযোগ্য ছিল না।

getoptখুব পুরানো এই সত্যটির একটি প্রমাণ হ'ল getopt(1)ম্যান পেজটি তার "$*"পরিবর্তে এখনও উল্লেখ করেছে "$@", এটি 1986 সালে বোর্ন শেলের সাথে একসাথে যুক্ত হয়েছিলgetopts(1) 1983 সালে শেল বিল্টিনের অভ্যন্তরের স্থানগুলির সাথে যুক্তিগুলি মোকাবেলা করার জন্য।

বিটিডাব্লু: আপনি যদি শেল স্ক্রিপ্টগুলিতে দীর্ঘ বিকল্পগুলি বিশ্লেষণ করতে আগ্রহী হন তবে এটি জানতে আগ্রহী হতে পারে যে getopt(3)libc (সোলারিস) থেকে বাস্তবায়ন এবং ksh93উভয়ই একটি অভিন্ন দীর্ঘ বিকল্প বাস্তবায়ন যুক্ত করেছে যা সংক্ষিপ্ত বিকল্পগুলির জন্য বিকল্প হিসাবে দীর্ঘ বিকল্পগুলি সমর্থন করে। এটি দীর্ঘ বিকল্পগুলির মাধ্যমে একটি অভিন্ন ইন্টারফেস বাস্তবায়নের কারণ ksh93এবং কারণ ।Bourne Shellgetopts

বোর্ন শেল ম্যান পৃষ্ঠা থেকে নেওয়া দীর্ঘ বিকল্পগুলির একটি উদাহরণ:

getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"

বোর্ন শেল এবং ksh93 উভয় ক্ষেত্রে কতক্ষণ বিকল্প বিকল্প ব্যবহার করা যেতে পারে তা দেখায়।

সাম্প্রতিক বোর্ন শেলের ম্যান পৃষ্ঠাটি দেখুন:

http://schillix.sourceforge.net/man/man1/bosh.1.html

ওপেনসোলারিস থেকে গিওপট (3) এর জন্য ম্যান পৃষ্ঠা:

http://schillix.sourceforge.net/man/man3c/getopt.3c.html

শেষ এবং পুরানো get * যাচাই করার জন্য getopt (1) ম্যান পৃষ্ঠা

http://schillix.sourceforge.net/man/man1/getopt.1.html


3

আমি একটি ভাল ব্যাশ সরঞ্জাম লিখতে একটি ব্যাশ সহায়ক লিখেছি

প্রকল্পের হোম: https://gitlab.mbedsys.org/mbedsys/bashopts

উদাহরণ:

#!/bin/bash -ei

# load the library
. bashopts.sh

# Enable backtrace dusplay on error
trap 'bashopts_exit_handle' ERR

# Initialize the library
bashopts_setup -n "$0" -d "This is myapp tool description displayed on help message" -s "$HOME/.config/myapprc"

# Declare the options
bashopts_declare -n first_name -l first -o f -d "First name" -t string -i -s -r
bashopts_declare -n last_name -l last -o l -d "Last name" -t string -i -s -r
bashopts_declare -n display_name -l display-name -t string -d "Display name" -e "\$first_name \$last_name"
bashopts_declare -n age -l number -d "Age" -t number
bashopts_declare -n email_list -t string -m add -l email -d "Email adress"

# Parse arguments
bashopts_parse_args "$@"

# Process argument
bashopts_process_args

সাহায্য দেবে:

NAME:
    ./example.sh - This is myapp tool description displayed on help message

USAGE:
    [options and commands] [-- [extra args]]

OPTIONS:
    -h,--help                          Display this help
    -n,--non-interactive true          Non interactive mode - [$bashopts_non_interactive] (type:boolean, default:false)
    -f,--first "John"                  First name - [$first_name] (type:string, default:"")
    -l,--last "Smith"                  Last name - [$last_name] (type:string, default:"")
    --display-name "John Smith"        Display name - [$display_name] (type:string, default:"$first_name $last_name")
    --number 0                         Age - [$age] (type:number, default:0)
    --email                            Email adress - [$email_list] (type:string, default:"")

উপভোগ করুন :)


আমি ম্যাক ওএস এক্স এ পেয়েছি: `` `lib / bashopts.sh: লাইন 138: ঘোষণা: -A: অবৈধ বিকল্প ঘোষণা: ব্যবহার: ঘোষণা [-afFirtx] [-p] [নাম [= মান] ...] Lib / bashopts.sh এ ত্রুটি: 138। 'ডিক্লেয়ার-এক্স -এ বাশপটস_পটপ্রপ_নাম' স্ট্যাটাস সহ 2 কল ট্রি: 1: lib / controller.sh: 4 উত্স (...) স্ট্যাটাসটি দিয়ে বের হচ্ছে 1 `` `
জোশ ওল্ফ

এটি ব্যবহারের জন্য আপনার বাশ সংস্করণ 4 প্রয়োজন। ম্যাক-এ, ডিফল্ট সংস্করণটি 3 You আপনি বাশ 4 ইনস্টল করতে হোম ব্রু ব্যবহার করতে পারেন
জোশ ওল্ফ

3

এখানে আমার পদ্ধতির - regexp ব্যবহার করে।

  • কোন getopts
  • এটি সংক্ষিপ্ত পরামিতিগুলির ব্লক পরিচালনা করে -qwerty
  • এটি সংক্ষিপ্ত পরামিতি পরিচালনা করে -q -w -e
  • এটি দীর্ঘ বিকল্পগুলি পরিচালনা করে --qwerty
  • আপনি সংক্ষিপ্ত বা দীর্ঘ বিকল্পটিতে অ্যাট্রিবিউটটি পাস করতে পারেন (আপনি যদি সংক্ষিপ্ত বিকল্পগুলির ব্লক ব্যবহার করে থাকেন তবে বৈশিষ্ট্যটি শেষ বিকল্পের সাথে সংযুক্ত থাকে)
  • আপনি স্পেস ব্যবহার করতে পারেন বা =বৈশিষ্ট্য সরবরাহ করতে, তবে হাইফেন + স্পেস "ডিলিমিটার" এর মুখোমুখি হওয়া পর্যন্ত অ্যাট্রিবিউট ম্যাচগুলি, তাই এর মধ্যে --q=qwe ty qwe tyএকটি বৈশিষ্ট্য রয়েছে
  • এটি সর্বোপরি সমস্ত মিশ্রণ পরিচালনা করে তাই -o a -op attr ibute --option=att ribu te --op-tion attribute --option att-ributeবৈধ

লিপি:

#!/usr/bin/env sh

help_menu() {
  echo "Usage:

  ${0##*/} [-h][-l FILENAME][-d]

Options:

  -h, --help
    display this help and exit

  -l, --logfile=FILENAME
    filename

  -d, --debug
    enable debug
  "
}

parse_options() {
  case $opt in
    h|help)
      help_menu
      exit
     ;;
    l|logfile)
      logfile=${attr}
      ;;
    d|debug)
      debug=true
      ;;
    *)
      echo "Unknown option: ${opt}\nRun ${0##*/} -h for help.">&2
      exit 1
  esac
}
options=$@

until [ "$options" = "" ]; do
  if [[ $options =~ (^ *(--([a-zA-Z0-9-]+)|-([a-zA-Z0-9-]+))(( |=)(([\_\.\?\/\\a-zA-Z0-9]?[ -]?[\_\.\?a-zA-Z0-9]+)+))?(.*)|(.+)) ]]; then
    if [[ ${BASH_REMATCH[3]} ]]; then # for --option[=][attribute] or --option[=][attribute]
      opt=${BASH_REMATCH[3]}
      attr=${BASH_REMATCH[7]}
      options=${BASH_REMATCH[9]}
    elif [[ ${BASH_REMATCH[4]} ]]; then # for block options -qwert[=][attribute] or single short option -a[=][attribute]
      pile=${BASH_REMATCH[4]}
      while (( ${#pile} > 1 )); do
        opt=${pile:0:1}
        attr=""
        pile=${pile/${pile:0:1}/}
        parse_options
      done
      opt=$pile
      attr=${BASH_REMATCH[7]}
      options=${BASH_REMATCH[9]}
    else # leftovers that don't match
      opt=${BASH_REMATCH[10]}
      options=""
    fi
    parse_options
  fi
done

এটার মত. নতুন লাইনের সাথে প্রতিধ্বনি করতে কেবল অ্যাড-পারম যুক্ত করুন।
mauron85

3

ধরে নিন আমরা test_args.shঅনুসরণের নামে একটি শেল স্ক্রিপ্ট তৈরি করি

#!/bin/sh
until [ $# -eq 0 ]
do
  name=${1:1}; shift;
  if [[ -z "$1" || $1 == -* ]] ; then eval "export $name=true"; else eval "export $name=$1"; shift; fi  
done
echo "year=$year month=$month day=$day flag=$flag"

আমরা নিম্নলিখিত কমান্ড চালানোর পরে:

sh test_args.sh  -year 2017 -flag  -month 12 -day 22 

আউটপুটটি হবে:

year=2017 month=12 day=22 flag=true

5
এটি নোহের উত্তরের মতো একই পদ্ধতির গ্রহণ করে তবে এর চেয়ে কম সুরক্ষা চেক / সুরক্ষার ব্যবস্থা রয়েছে। এটি আমাদের স্ক্রিপ্টের পরিবেশে স্বেচ্ছাসেবী যুক্তি লেখার অনুমতি দেয় এবং আমি নিশ্চিত যে এখানে আপনার ব্যবহারের ফলে কমান্ড ইনজেকশন মঞ্জুর হতে পারে।
বার্নওয়েল


2

অবস্থানগত এবং পতাকা-ভিত্তিক যুক্তিগুলির মিশ্রণ

--param = আরগ (সমান সমান)

অবস্থানগত আর্গুমেন্টের মধ্যে নিখরচায় পতাকা মিশ্রণ:

./script.sh dumbo 127.0.0.1 --environment=production -q -d
./script.sh dumbo --environment=production 127.0.0.1 --quiet -d

মোটামুটি সংক্ষিপ্ত পদ্ধতির মাধ্যমে সম্পাদন করা যেতে পারে:

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   param=${!pointer}
   if [[ $param != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      case $param in
         # paramter-flags with arguments
         -e=*|--environment=*) environment="${param#*=}";;
                  --another=*) another="${param#*=}";;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + 1)):$#} \
         || set -- ${@:((pointer + 1)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

- পরিমাপ আর্গ (স্থান সীমিত)

এটি মেশানো --flag=valueএবং --flag valueশৈলীগুলি না করা স্বাভাবিক ।

./script.sh dumbo 127.0.0.1 --environment production -q -d

এটি পড়ার জন্য কিছুটা দ্বিধাহীন, তবে এটি এখনও বৈধ

./script.sh dumbo --environment production 127.0.0.1 --quiet -d

সূত্র

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   if [[ ${!pointer} != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      param=${!pointer}
      ((pointer_plus = pointer + 1))
      slice_len=1

      case $param in
         # paramter-flags with arguments
         -e|--environment) environment=${!pointer_plus}; ((slice_len++));;
                --another) another=${!pointer_plus}; ((slice_len++));;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + $slice_len)):$#} \
         || set -- ${@:((pointer + $slice_len)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

2

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

মূলত eval "local key='val'"

function myrsync() {

        local backup=("${@}") args=(); while [[ $# -gt 0 ]]; do k="$1";
                case "$k" in
                    ---sourceuser|---sourceurl|---targetuser|---targeturl|---file|---exclude|---include)
                        eval "local ${k:3}='${2}'"; shift; shift    # Past two arguments
                    ;;
                    *)  # Unknown option  
                        args+=("$1"); shift;                        # Past argument only
                    ;;                                              
                esac                                                
        done; set -- "${backup[@]}"                                 # Restore $@


        echo "${sourceurl}"
}

এখানে সর্বাধিক উত্তর হিসাবে গ্লোবালের পরিবর্তে স্থানীয় হিসাবে ভেরিয়েবলগুলি ঘোষণা করে।

নামে পরিচিত:

myrsync ---sourceurl http://abc.def.g ---sourceuser myuser ... 

$ {K: 3 মূলত প্রথমটি ---কী থেকে সরানোর জন্য একটি স্ট্রিং থাকে ।


1

এটি জানার জন্যও দরকারী হতে পারে, আপনি একটি মান সেট করতে পারেন এবং যদি কেউ ইনপুট সরবরাহ করে তবে সেই মানটি দিয়ে ডিফল্টটিকে ওভাররাইড করুন ..

myscript.sh -f ./serverlist.txt বা ঠিক ./myscript.sh (এবং এটি ডিফল্ট নেয়)

    #!/bin/bash
    # --- set the value, if there is inputs, override the defaults.

    HOME_FOLDER="${HOME}/owned_id_checker"
    SERVER_FILE_LIST="${HOME_FOLDER}/server_list.txt"

    while [[ $# > 1 ]]
    do
    key="$1"
    shift

    case $key in
        -i|--inputlist)
        SERVER_FILE_LIST="$1"
        shift
        ;;
    esac
    done


    echo "SERVER LIST   = ${SERVER_FILE_LIST}"

1

গিওপট [গুলি], পসিক্স, পুরানো ইউনিক্স শৈলী ছাড়াই আর একটি সমাধান

ব্রুনো ব্রোনোস্কি এখানে পোস্ট করেছেন এমন সমাধানের অনুরূপ ব্যবহার ব্যতীত এটি একটি getopt(s)

আমার সমাধানের মূল পার্থক্যমূলক বৈশিষ্ট্যটি হ'ল এটি tar -xzf foo.tar.gzসমান এর মতো বিকল্পগুলি একসাথে সংমিশ্রিত করতে দেয় tar -x -z -f foo.tar.gz। এবং ঠিক যেমন tar, psইত্যাদি the সংক্ষিপ্ত বিকল্পগুলির একটি ব্লকের জন্য নেতৃস্থানীয় হাইফেন alচ্ছিক (তবে এটি সহজেই পরিবর্তন করা যেতে পারে)। দীর্ঘ বিকল্পগুলিও সমর্থিত হয় (তবে যখন ব্লকটি শুরু হয় তখন দুটি শীর্ষস্থানীয় হাইফেনের প্রয়োজন হয়)।

উদাহরণ অপশন সহ কোড

#!/bin/sh

echo
echo "POSIX-compliant getopt(s)-free old-style-supporting option parser from phk@[se.unix]"
echo

print_usage() {
  echo "Usage:

  $0 {a|b|c} [ARG...]

Options:

  --aaa-0-args
  -a
    Option without arguments.

  --bbb-1-args ARG
  -b ARG
    Option with one argument.

  --ccc-2-args ARG1 ARG2
  -c ARG1 ARG2
    Option with two arguments.

" >&2
}

if [ $# -le 0 ]; then
  print_usage
  exit 1
fi

opt=
while :; do

  if [ $# -le 0 ]; then

    # no parameters remaining -> end option parsing
    break

  elif [ ! "$opt" ]; then

    # we are at the beginning of a fresh block
    # remove optional leading hyphen and strip trailing whitespaces
    opt=$(echo "$1" | sed 's/^-\?\([a-zA-Z0-9\?-]*\)/\1/')

  fi

  # get the first character -> check whether long option
  first_chr=$(echo "$opt" | awk '{print substr($1, 1, 1)}')
  [ "$first_chr" = - ] && long_option=T || long_option=F

  # note to write the options here with a leading hyphen less
  # also do not forget to end short options with a star
  case $opt in

    -)

      # end of options
      shift
      break
      ;;

    a*|-aaa-0-args)

      echo "Option AAA activated!"
      ;;

    b*|-bbb-1-args)

      if [ "$2" ]; then
        echo "Option BBB with argument '$2' activated!"
        shift
      else
        echo "BBB parameters incomplete!" >&2
        print_usage
        exit 1
      fi
      ;;

    c*|-ccc-2-args)

      if [ "$2" ] && [ "$3" ]; then
        echo "Option CCC with arguments '$2' and '$3' activated!"
        shift 2
      else
        echo "CCC parameters incomplete!" >&2
        print_usage
        exit 1
      fi
      ;;

    h*|\?*|-help)

      print_usage
      exit 0
      ;;

    *)

      if [ "$long_option" = T ]; then
        opt=$(echo "$opt" | awk '{print substr($1, 2)}')
      else
        opt=$first_chr
      fi
      printf 'Error: Unknown option: "%s"\n' "$opt" >&2
      print_usage
      exit 1
      ;;

  esac

  if [ "$long_option" = T ]; then

    # if we had a long option then we are going to get a new block next
    shift
    opt=

  else

    # if we had a short option then just move to the next character
    opt=$(echo "$opt" | awk '{print substr($1, 2)}')

    # if block is now empty then shift to the next one
    [ "$opt" ] || shift

  fi

done

echo "Doing something..."

exit 0

উদাহরণ ব্যবহারের জন্য দয়া করে নীচে আরও উদাহরণ দেখুন।

যুক্তিযুক্ত বিকল্পগুলির অবস্থান

তাত্পর্যপূর্ণ মূল্যগুলির জন্য আর্গুমেন্টগুলির সাথে বিকল্পগুলি সর্বশেষ হবে না (কেবল দীর্ঘ বিকল্পগুলি হওয়া দরকার)। উদাহরণস্বরূপ, উদাহরণস্বরূপ tar(অন্তত কিছু বাস্তবায়নের ক্ষেত্রে) fবিকল্পগুলি শেষ হওয়া দরকার কারণ ফাইলের নামটি অনুসরণ করে ( tar xzf bar.tar.gzকাজ করে তবে tar xfz bar.tar.gzতা করে না) এখানে এটি হয় না (পরবর্তী উদাহরণগুলি দেখুন)।

যুক্তি সহ একাধিক বিকল্প

অন্য বোনাস হিসাবে অপশন প্যারামিটারগুলি প্রয়োজনীয় বিকল্পগুলির সাথে পরামিতিগুলির দ্বারা বিকল্পগুলির ক্রমে গ্রাস করা হয়। কমান্ড লাইন abc X Y Z(বা -abc X Y Z) দিয়ে এখানে কেবল আমার স্ক্রিপ্টের আউটপুট দেখুন :

Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!

দীর্ঘ অপশন পাশাপাশি সংক্ষিপ্ত

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

  • -cba Z Y X
  • cba Z Y X
  • -cb-aaa-0-args Z Y X
  • -c-bbb-1-args Z Y X -a
  • --ccc-2-args Z Y -ba X
  • c Z Y b X a
  • -c Z Y -b X -a
  • --ccc-2-args Z Y --bbb-1-args X --aaa-0-args

এই সমস্ত বাড়ে:

Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...

এই সমাধানে নয়

.চ্ছিক যুক্তি

Workচ্ছিক আর্গুমেন্ট সহ বিকল্পগুলি কিছুটা কাজের দ্বারা সম্ভব হওয়া উচিত, উদাহরণস্বরূপ হাইফেন ছাড়া কোনও ব্লক আছে কি না তা প্রত্যাশা করে; ব্যবহারকারীকে তখন প্রতিটি ব্লকের সামনে একটি হাইফেন লাগানো দরকার যা একটি followingচ্ছিক পরামিতিযুক্ত একটি পরামিতি সহ একটি ব্লক অনুসরণ করে। সম্ভবত এটি ব্যবহারকারীর সাথে যোগাযোগের জন্য জটিল কারণ এত ভাল এই ক্ষেত্রে পুরোপুরি একটি শীর্ষস্থানীয় হাইফেন প্রয়োজন।

একাধিক সম্ভাব্য পরামিতিগুলির সাথে জিনিসগুলি আরও জটিল হয়ে ওঠে। আমি যুক্তিটি তার পক্ষে যুক্তিযুক্ত কিনা তা নির্ধারণ করে স্মার্ট হওয়ার অপশনগুলি তৈরি করার বিরুদ্ধে পরামর্শ দেব (উদাহরণস্বরূপ একটি বিকল্পের সাথে কেবল একটি সংখ্যাকে alচ্ছিক যুক্তি হিসাবে নেওয়া হয়) কারণ এটি ভবিষ্যতে ভঙ্গ হতে পারে।

আমি ব্যক্তিগতভাবে optionচ্ছিক আর্গুমেন্টের পরিবর্তে অতিরিক্ত বিকল্পের পক্ষে।

একটি সমান চিহ্ন সহ বিকল্প বিকল্প যুক্তি

ঠিক যেমন optionচ্ছিক যুক্তি দিয়ে আমি এর ভক্ত নই (বিটিডাব্লু, বিভিন্ন প্যারামিটার শৈলীর উপকারিতা / কনস নিয়ে আলোচনার জন্য কোনও থ্রেড আছে?) তবে আপনি যদি এটি চান তবে আপনি সম্ভবত এটি নিজেই বাস্তবায়িত করতে পারেন ঠিক যেমন http: // এ করা হয়েছিল mywiki.wooledge.org/BashFAQ/035#--long-with-arg=?* কেস স্টেটমেন্ট সহ ম্যানুয়াল_লুপ এবং তারপরে সমান চিহ্নটি সরিয়ে ফেলা (এটি সেই সাইটটি বিটিডাব্লু যা বলে যে প্যারামিটার কনটেন্টেশন তৈরি করা কিছু প্রচেষ্টা দিয়ে সম্ভব তবে "বামে [এটিকে] পাঠকের অনুশীলন হিসাবে) "যা তাদের কথায় আমি তাদের গ্রহণ করতে বাধ্য করলাম তবে আমি শুরু থেকে শুরু করেছি)।

অন্যান্য নোট

পজিএক্স-সম্মতিযুক্ত, এমনকি প্রাচীন ব্যাসিবক্স সেটআপগুলিতেও কাজ করে যা আমাকে মোকাবেলা করতে হয়েছিল (উদাহরণস্বরূপ cut, headএবং getoptsনিখোঁজ)।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.