programing

Bash 명령줄 인수를 해석하려면 어떻게 해야 하나요?

javajsp 2023. 4. 24. 22:26

Bash 명령줄 인수를 해석하려면 어떻게 해야 하나요?

예를 들어, 다음 행으로 호출되는 스크립트가 있습니다.

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

또는 다음과 같습니다.

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

의 조합)에서할 수 해석 $v,$f , , , , 입니다.$d 모 will will will will will 로 설정됩니다.true ★★★★★★★★★★★★★★★★★」$outFile 되다/fizz/someOtherFile

구분 Bash 스페이스 구분):--option argument)

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

POSITIONAL_ARGS=()

while [[ $# -gt 0 ]]; do
  case $1 in
    -e|--extension)
      EXTENSION="$2"
      shift # past argument
      shift # past value
      ;;
    -s|--searchpath)
      SEARCHPATH="$2"
      shift # past argument
      shift # past value
      ;;
    --default)
      DEFAULT=YES
      shift # past argument
      ;;
    -*|--*)
      echo "Unknown option $1"
      exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done

set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
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 /etc/hosts
위의 블록 복사 붙여넣기 출력
FILE EXTENSION  = conf
SEARCH PATH     = /etc
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
사용.
demo-space-separated.sh -e conf -s /etc /etc/hosts

Equals-Separated Bash Equals-Separated("))--option=argument)

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
      ;;
    --default)
      DEFAULT=YES
      shift # past argument with no value
      ;;
    -*|--*)
      echo "Unknown option $i"
      exit 1
      ;;
    *)
      ;;
  esac
done

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
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 /etc/hosts
위의 블록 복사 붙여넣기 출력
FILE EXTENSION  = conf
SEARCH PATH     = /etc
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
사용.
demo-equals-separated.sh -e=conf -s=/etc /etc/hosts

「 」를 보다 잘 ${i#*=} 가이드에서 "서브스트링 제거"를 검색합니다.그것은 기능적으로 와 동등하다.`sed 's/[^=]*=//' <<< "$i"` 또는 "Subprocess"를 합니다.`echo "$i" | sed 's/[^=]*=//'`두 개의 불필요한 하위 프로세스를 호출합니다.


getopt에서 bash 사용

1syslog, getopt (1) 표표표 ( 「 」, 「 」)getopt★★★★★

  • 빈 문자열인 인수를 처리할 수 없습니다.
  • 공백이 포함된 인수를 처리할 수 없습니다.

★★★★★getopt버전에는 이러한 제한이 없습니다.상세한 것에 대하여는, 다음의 문서를 참조해 주세요.


POSIX의 getopts

쉘 은 「POSIX」를 제공하고 있습니다.getopts이런 제약이 없는 곳이죠. 것을 getoptsexample를 참조해 주세요.

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
사용.
demo-getopts.sh -vf /etc/hosts foo bar

getopts과 같습니다

  1. 할 수 .dash.
  2. 여러 의 단일 할 수 .-vf filename유닉스

「 」의 getopts(shortoptions)밖에할 수 입니다.-h 아니라, 이에요.--help을 사용하다

모든 구문과 변수의 의미를 설명하는 getopts 튜토리얼이 있습니다.bash에는 또help getopts참고가 될 수도 있습니다.

No answer는 향상된 getopt을 보여줍니다. 그리고 가장 많이 투표된 답변은 오해의 소지가 있습니다.무시하거나-⁠vfd스타일 단축 옵션(OP에 의해 요구됨) 또는 positional 인수 뒤에 있는 옵션(OP에 의해 요구됨)이 있으며 구문 분석 오류는 무시됩니다.★★★★

  • util-linux 또는 이전의 GNU 1glibc에서 확장 버전을 사용합니다.
  • 와 함께 동작합니다.getopt_long()GNU glibc C.
  • 이 페이지의 다른 솔루션으로는 이 모든 것을 수행할 수 없습니다.
    • 는 공백, 따옴표 및 인수 이진수를2 처리합니다(비문자).getopt수 없다)
    • 할 수 .script.sh -o outFile file1 file2 -v )getopts는 하지 않습니다)
    • =- options : - style 긴옵:::: :script.sh --outfile=fileOut --infile fileIn 파싱의 경우 둘 다 합니다.) (자체파싱의 둘 다 장황합니다.)
    • 숏옵션을할 수 을 사용할 수 있습니다).-vfd해석의 ) (자체 해석의 경우)
    • 에서는, 하는 option-displaces(예를 들면, 「가 됩니다.-oOutfile ★★★★★★★★★★★★★★★★★」-vfdoOutfile
  • 이미 오래된3 GNU 시스템에서 이를 찾을 수 없습니다(예를 들어 Linux에 있는 경우).
  • 는 다음과 같이 할 수 .getopt --test 4 → 반환값 4.
  • other.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
# More safety, by turning some bugs into errors.
# Without `errexit` you don’t need ! and can replace
# ${PIPESTATUS[0]} with a simple $?, but I prefer safety.
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

# option --output/-o requires 1 argument
LONGOPTS=debug,force,output:,verbose
OPTIONS=dfo:v

# -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 확장 getopt는 Cygwin을 포함한 대부분의 "bash-systems"에서 사용할 수 있습니다.OS X에서 brew install gnu-getopt 또는sudo port install getopt
2 POSIXexec() 있는 을 조기에 NULL로 끝납니다.이 바이트들은 인수를 조기에 종료합니다.
3 1997년 또는 그 이전에 발매된 첫 번째 버전(1997년까지만 추적)

deploy.sh

#!/bin/bash

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

echo "Where to deploy: $target"
echo "Should uglify  : $uglify"

사용방법:

./deploy.sh -t dev -u

# OR:

./deploy.sh --target dev --uglify

digitalpeer.com 에서 약간의 변경을 가했습니다.

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"` 또는 "Subprocess"를 합니다.`echo "$i" | sed 's/[^=]*=//'`두 개의 불필요한 하위 프로세스를 호출합니다.

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

이 솔루션은 다음과 같습니다.

  • 「」-n arg ★★★★★★★★★★★★★★★★★」--name=arg
  • 마지막에 인수를 허용합니다.
  • 철자가 틀린 경우 정상적인 오류를 보여줍니다.
  • 호환, bashism 사용 안 함
  • 읽기 가능, 루프 상태 유지 필요 없음

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 중 하나가 허용되지만 -c 뒤에 인수가 붙는다는 것입니다('c:'는 이를 나타냅니다).

이것을 「g」라고 부르고, 시험해 보면,

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

먼저 두 가지 인수로 시작하고 "getopt"는 옵션을 분할하여 각각의 인수에 넣습니다.또, 「--」도 추가되어 있습니다.

스크립트로 포터블 파싱을 쓰는 것이 너무 답답해서 Argbash를 작성했습니다.Argbash는 스크립트의 인수 파싱 코드를 생성할 수 있는 FOSS 코드 생성기입니다.또한 다음과 같은 기능이 있습니다.

https://argbash.io

나는 이전의 답변을 나의 오래된 애드혹 파라미터 파싱을 정리하기 위한 출발점으로 사용했다.그리고 다음 템플릿 코드를 리팩터링했습니다.= 또는 공백으로 구분된 인수와 함께 그룹화된 여러 개의 짧은 매개 변수를 사용하여 긴 매개 변수와 짧은 매개 변수를 모두 처리합니다.마지막으로 $1,$2에 param 이외의 인수를 다시 삽입합니다.변수입니다.

#!/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
# 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

그리고 둘 다 같은 최종 결과를 얻어야 합니다.

장점:

  • -syslog=value 및 -syslog 값을 모두 사용할 수 있습니다.

  • bash에서 사용할 수 있는 임의의 arg 이름으로 동작합니다.

    • 의미 -a, -arg, -arg, -a-r-g 또는 기타
  • 완전 배시.getopt 또는 getopts를 학습/사용할 필요가 없음

단점:

  • arg를 결합할 수 없습니다.

    • 즉 -abc는 없습니다.-a -b -c를 수행해야 합니다.

에서는 '먹다'를 사용하는 줍니다.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

간결하고 요령 있게 읽을 수 있으며 거의 모든 것을 처리합니다(IMHO).

그게 도움이 됐으면 좋겠어요.

ASAP: 다른 셸 인수 파서

편집 메모: 버전 2.0, 순수 POSIX 코드와 글루텐 프리!

TL;DR

셸하여 POSIX 형식의합니다.-o [ARG],-abo [ARG],--opt [ARG] ★★★★★★★★★★★★★★★★★」--opt=[ARG]서, snowledge.ARG는 옵션 인수입니다.인수가 되어 있을 만 아니라 「혼재하다」도 할 수 .--될 수 하다.'

명령어가 올바르면, 즉 거의 검사를 수행하지 않는 최소한의 버전입니다. 스크립트의 맨 위에 붙여 넣을 수 있습니다.함수로서 기능하지 않습니다.옵션 정의를 대체할 수 있습니다.

#!/bin/sh -e

USAGE="Usage:  ${CMD:=${0##*/}} [(-v|--verbose)] [--name=TEXT] [(-o|--output) FILE] [ARGS...]"

exit2 () { printf >&2 "%s:  %s: '%s'\n%s\n" "$CMD" "$1" "$2" "$USAGE"; exit 2; }
check () { { [ "$1" != "$EOL" ] && [ "$1" != '--' ]; } || exit2 "missing argument" "$2"; }  # avoid infinite loop

# parse command-line options
set -- "$@" "${EOL:=$(printf '\1\3\3\7')}"  # end-of-list marker
while [ "$1" != "$EOL" ]; do
  opt="$1"; shift
  case "$opt" in

    #EDIT HERE: defined options
         --name    ) check "$1" "$opt"; opt_name="$1"; shift;;
    -o | --output  ) check "$1" "$opt"; opt_output="$1"; shift;;
    -v | --verbose ) opt_verbose='true';;
    -h | --help    ) printf "%s\n" "$USAGE"; exit 0;;

    # process special cases
    --) while [ "$1" != "$EOL" ]; do set -- "$@" "$1"; shift; done;;   # parse remaining as positional
    --[!=]*=*) set -- "${opt%%=*}" "${opt#*=}" "$@";;                  # "--opt=arg"  ->  "--opt" "arg"
    -[A-Za-z0-9] | -*[!A-Za-z0-9]*) exit2 "invalid option" "$opt";;    # anything invalid like '-*'
    -?*) other="${opt#-?}"; set -- "${opt%$other}" "-${other}" "$@";;  # "-abc"  ->  "-a" "-bc"
    *) set -- "$@" "$opt";;                                            # positional, rotate to the end
  esac
done; shift # $EOL

printf "name = '%s'\noutput = '%s'\nverbose = '%s'\n\$@ = (%s)\n" \
    "$opt_name" "$opt_output" "$opt_verbose" "$*"

샘플 출력

$ ./asap-example.sh -vo path/to/camelot 'spam?' --name=Arthur 'spam!' -- +42 -17
name = 'Arthur'
output = 'path/to/camelot'
verbose = 'true'
$@ = (spam? spam! +42 -17)
$ ./asap-example.sh -name Lancelot eggs bacon
asap-example.sh:  invalid option: '-n'
Usage:  asap-example.sh [(-v|--verbose)] [--name=TEXT] [(-o|--output) FILE] [ARG...]

묘사

저는 @bronson의 비교적 간단한 답변에 영감을 받아 (너무 복잡하지 않게) 개선하려고 합니다.

이 파서 실장에서는 패턴 매칭, 파라미터 확장 및 셸의 자체 위치 파라미터를 출력 제한 큐로 사용하여 인수를 루프오버 및 처리합니다.결과는 다음과 같습니다.

  • the any any any any any -o [ARG],-abo [ARG],--long-option [ARG] ... --long-option=[ARG]옵션 스타일을 사용할 수 있습니다.
  • 인수는 임의의 순서로 발생할 수 있습니다.인수는 위치에 있는 것만 남습니다. $@
  • 사용하다 -- 나머지 주장을 위치 결정으로 취급하도록 강제한다.
  • 직교 기능을 갖춘 휴대성, 콤팩트, 가독성.
  • 하지 않다getopt(s)또는 외부 유틸리티
  • 유효하지 않은 옵션과 누락된 인수를 검출합니다.

휴대성

, this 、 of 、 of of 、 음음음음 of this 。bash,dash,mksh,ksh93,yash,zsh Busy의 [Busy Box]ash패스를 하여 호출됩니다.이 패스는 (「」가 ./bin/sh를 참조해 주세요.

버그가 발견되거나 특정 POSIX 호환 쉘에서 작동하지 않는 경우 의견을 남겨주세요.


PS: 알아요...2진수 값을 갖는 인수0x01030307하고 있는 마지막.

@bruno-bronosky의 답변을 바탕으로 일반적인 포맷을 처리하기 위해 "프리프로세서"를 추가했습니다.

  • ★★를 합니다.--longopt=val--longopt val
  • ★★를 합니다.-xyz-x -y -z
  • " " "--
  • 예기치 않은 옵션에 대한 오류를 표시합니다.
  • 콤팩트하고 읽기 쉬운 옵션 스위치
#!/bin/bash

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

invalid() {
  echo "ERROR: Unrecognized argument: $1" >&2
  usage
  exit 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") ;;
    -*) 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; exit 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[@]}"

다른 유틸리티와 호환성이 있는 스크립트를 작성하는 경우는, 이하의 유연성이 도움이 됩니다.

다음 중 하나:

command -x=myfilename.ext --another_switch 

또는 다음 중 하나를 선택합니다.

command -x myfilename.ext --another_switch

코드는 다음과 같습니다.

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

이 제품은 다음과 같이 간단하게 사용할 수법은 다음과 같습니다.

#!/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

가 너에게 기능 내가 주는 기능parse_params커맨드 라인에서 파라미터를 해석합니다.

  1. 추가 유틸리티가 없는 순수한 Bash 솔루션입니다.
  2. 글로벌 범위를 오염시키지 않습니다.
  3. 논리를 더욱 구축할 수 있는 사용하기 쉬운 변수를 쉽게 반환합니다.
  4. 앞의 (대시)의 양은가 되지 .--all는 「」와 같습니다.-all는 「」와 같습니다.all=all)

다음 스크립트는 복사 붙여넣기 작업 시연입니다. 것은, 을 참조하십시오.show_use을 하기 위한 parse_params.

제한 사항:

  1. 으로 구분된 「」 「」 「」 「」)는되고 있지 .-d 1)
  2. 를 잃기 에 대시는 없어집니다.--any-param ★★★★★★★★★★★★★★★★★」-anyparam
  3. eval $(parse_params "$@")bash 함수 내에서 사용해야 합니다(글로벌 범위에서는 작동하지 않습니다).

#!/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

getopts는 #1이 설치되어 있고 #2가 동일한 플랫폼에서 실행하려는 경우 정상적으로 작동합니다.OSX와 Linux(예를 들어)의 동작은 이 점에서 다릅니다.

다음은 등가 플래그, 등가 플래그 및 부울 플래그를 지원하는 (비 getopts) 솔루션입니다.예를 들어 다음과 같은 방법으로 스크립트를 실행할 수 있습니다.

./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

또 다른 옵션 파서(제너레이터)

셸 스크립트용 우아한 옵션 파서(모든 POSIX 쉘에 대한 풀 지원) https://github.com/ko1nksm/getoptions (업데이트: v3.3.0은 2021-05-02)

getoptions는 POSIX 호환 셸 스크립트로 작성된 새로운 옵션 파서(제너레이터)로 2020년 8월에 출시되었습니다.셸 스크립트에서 POSIX/GNU 스타일의 옵션 구문을 지원하는 사용자를 위한 것입니다.

은 '하다' 입니다.-a,+a,-abc,-vvv,-p VALUE,-pVALUE,--flag,--no-flag,--with-flag,--without-flag,--param VALUE,--param=VALUE,--option[=VALUE],--no-option --.

하위 명령, 검증, 생략 옵션 및 자동 도움말 생성을 지원합니다.또한 모든 POSIX 쉘(대시 0.5.4+, bash 2.03+, ksh88+, mksh R28+, zsh 3.1.9+, yash 2.29+, busybox ash 1.1.3+ 등)과 연동됩니다.

#!/bin/sh

VERSION="0.1"

parser_definition() {
  setup   REST help:usage -- "Usage: example.sh [options]... [arguments]..." ''
  msg -- 'Options:'
  flag    FLAG    -f --flag                 -- "takes no arguments"
  param   PARAM   -p --param                -- "takes one argument"
  option  OPTION  -o --option on:"default"  -- "takes one optional argument"
  disp    :usage  -h --help
  disp    VERSION    --version
}

eval "$(getoptions parser_definition) exit 1"

echo "FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION"
printf '%s\n' "$@" # rest arguments

다음 인수를 해석합니다.

example.sh -f --flag -p VALUE --param VALUE -o --option -oVALUE --option=VALUE 1 2 3

자동 도움말 생성도 가능합니다.

$ example.sh --help

Usage: example.sh [options]... [arguments]...

Options:
  -f, --flag                  takes no arguments
  -p, --param PARAM           takes one argument
  -o, --option[=OPTION]       takes one optional argument
  -h, --help
      --version

또한 옵션 구문 분석기 생성기로 다음과 같은 간단한 옵션 구문 분석 코드를 생성합니다.코드를 성성드 if if는 필요 .getoptions진정한 휴대성과 의존성 제로를 실현합니다.

FLAG=''
PARAM=''
OPTION=''
REST=''
getoptions_parse() {
  OPTIND=$(($#+1))
  while OPTARG= && [ $# -gt 0 ]; do
    case $1 in
      --?*=*) OPTARG=$1; shift
        eval 'set -- "${OPTARG%%\=*}" "${OPTARG#*\=}"' ${1+'"$@"'}
        ;;
      --no-*|--without-*) unset OPTARG ;;
      -[po]?*) OPTARG=$1; shift
        eval 'set -- "${OPTARG%"${OPTARG#??}"}" "${OPTARG#??}"' ${1+'"$@"'}
        ;;
      -[fh]?*) OPTARG=$1; shift
        eval 'set -- "${OPTARG%"${OPTARG#??}"}" -"${OPTARG#??}"' ${1+'"$@"'}
        OPTARG= ;;
    esac
    case $1 in
      '-f'|'--flag')
        [ "${OPTARG:-}" ] && OPTARG=${OPTARG#*\=} && set "noarg" "$1" && break
        eval '[ ${OPTARG+x} ] &&:' && OPTARG='1' || OPTARG=''
        FLAG="$OPTARG"
        ;;
      '-p'|'--param')
        [ $# -le 1 ] && set "required" "$1" && break
        OPTARG=$2
        PARAM="$OPTARG"
        shift ;;
      '-o'|'--option')
        set -- "$1" "$@"
        [ ${OPTARG+x} ] && {
          case $1 in --no-*|--without-*) set "noarg" "${1%%\=*}"; break; esac
          [ "${OPTARG:-}" ] && { shift; OPTARG=$2; } || OPTARG='default'
        } || OPTARG=''
        OPTION="$OPTARG"
        shift ;;
      '-h'|'--help')
        usage
        exit 0 ;;
      '--version')
        echo "${VERSION}"
        exit 0 ;;
      --)
        shift
        while [ $# -gt 0 ]; do
          REST="${REST} \"\${$(($OPTIND-$#))}\""
          shift
        done
        break ;;
      [-]?*) set "unknown" "$1"; break ;;
      *)
        REST="${REST} \"\${$(($OPTIND-$#))}\""
    esac
    shift
  done
  [ $# -eq 0 ] && { OPTIND=1; unset OPTARG; return 0; }
  case $1 in
    unknown) set "Unrecognized option: $2" "$@" ;;
    noarg) set "Does not allow an argument: $2" "$@" ;;
    required) set "Requires an argument: $2" "$@" ;;
    pattern:*) set "Does not match the pattern (${1#*:}): $2" "$@" ;;
    notcmd) set "Not a command: $2" "$@" ;;
    *) set "Validation error ($1): $2" "$@"
  esac
  echo "$1" >&2
  exit 1
}
usage() {
cat<<'GETOPTIONSHERE'
Usage: example.sh [options]... [arguments]...

Options:
  -f, --flag                  takes no arguments
  -p, --param PARAM           takes one argument
  -o, --option[=OPTION]       takes one optional argument
  -h, --help
      --version
GETOPTIONSHERE
}

프로젝트를 제출하고 싶습니다.https://github.com/flyingangel/argparser

source argparser.sh
parse_args "$@"

그렇게 간단하다.환경은 인수와 이름이 같은 변수로 채워집니다.

스택의 상위 위치에서 동시에 실행되는 getopts가 중단되는 것을 방지하기 위한 함수는 다음과 같습니다.

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
...
}

다음을 가능하게 하는 옵션 구문 분석의 버전을 제안하고 싶습니다.

-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

cmdline arg를 해석하는 방법에는 몇 가지가 있습니다(예를 들어 GNU getopt(포터블이 아님) vs BSD(MacOS) getopt vs getopts).모두 문제가 있습니다.이 솔루션

  • 휴대할 수 있습니다.
  • 의존관계가 제로이며 bash 빌트인에만 의존합니다.
  • 짧은 옵션과 긴 옵션을 모두 사용할 수 있습니다.
  • 으로 처리하거나 할 수 있습니다.=
  • style 을 지원합니다.-vxf
  • 인수( 「」등 )를 사용하여 합니다.--color »--color=always
  • 알 수 없는 옵션을 올바르게 검출하여 보고하다
  • 는 「」를 서포트하고 있습니다.-- 및 옵션 신호를 보냅니다.
  • 같은 기능 세트의 대체 기능과 비교하여 코드 블러트가 필요하지 않습니다.즉, 간결하고 유지보수가 용이함

예:다음 중 하나

# 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=${@}"

여기 있는 다른 답변에 따르면 이 버전은 다음과 같습니다.

#!/bin/bash
set -e

function parse() {
    for arg in "$@"; do # transform long options to short ones
        shift
        case "$arg" in
            "--name") set -- "$@" "-n" ;;
            "--verbose") set -- "$@" "-v" ;;
            *) set -- "$@" "$arg"
        esac
    done

    while getopts "n:v" optname  # left to ":" are flags that expect a value, right to the ":" are flags that expect nothing
    do
        case "$optname" in
            "n") name=${OPTARG} ;;
            "v") verbose=true ;;
        esac
    done
    shift "$((OPTIND-1))" # shift out all the already processed options
}


parse "$@"
echo "hello $name"
if [ ! -z $verbose ]; then echo 'nice to meet you!'; fi

사용방법:

$ ./parse.sh
hello
$ ./parse.sh -n YOUR_NAME
hello YOUR_NAME
$ ./parse.sh -n YOUR_NAME -v
hello YOUR_NAME
nice to meet you!
$ ./parse.sh -v -n YOUR_NAME
hello YOUR_NAME
nice to meet you!
$ ./parse.sh -v
hello 
nice to meet you!

처리되지 않은 인수를 보존하는 솔루션.데모 포함

제 해결책은 이렇습니다.매우 유연하며 다른 제품과 달리 외부 패키지가 필요하지 않으며 남은 인수를 깔끔하게 처리합니다.

./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

장점: 처리 능력이 매우 뛰어납니다.여기에는 사용되지 않는 인수가 보존됩니다.다른 많은 솔루션에서는 그렇지 않습니다.또한 스크립트를 수동으로 정의하지 않고 변수를 호출할 수도 있습니다.또한 대응하는 인수가 없는 경우에도 변수를 미리 입력할 수 있습니다(자세한 예 참조).

단점: 단일 복잡한 arg 문자열을 구문 분석할 수 없습니다. 예를 들어 -xcvf는 단일 인수로 처리됩니다.하지만 이 기능을 추가한 코드를 내 코드에 쉽게 쓸 수 있습니다.

다음은 regexp를 사용한 접근법입니다.

  • getopts 없음
  • 합니다.-qwerty
  • 매개 를 처리합니다.-q -w -e
  • 합니다.--qwerty
  • 속성을 short 옵션 또는 long 옵션에 전달할 수 있습니다(short 옵션 블록을 사용하는 경우 속성은 마지막 옵션에 연결됩니다).
  • 또는 ""를 할 수 .="space"가에 "space"에서는 "space"가 됩니다.--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

위치 인수와 플래그 기반 인수 혼합

--syslog=syslog(구분 기호로 구분됨)

위치 인수 간에 플래그를 자유롭게 혼합:

./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

--syslog arg(스페이스 구분)

게요.--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

:getopt(1)AT&T를 사용하다

getopt는 1984년에 만들어졌지만 실제로 사용할 수 없었기 때문에 1986년에 이미 묻혀 있습니다.

★★★★★★★★★★★★★★★★★★★★★★의 증거getopt매우 시대에 뒤떨어져 있습니다.getopt(1)도 man이 언급되어 있다."$*""$@" 본 셸과 본getopts(1)셸은 내부에 공백이 있는 인수를 처리하기 위해 내장되어 있습니다.

데 경우 BTW: " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " 。getopt(3)및 libc(Solaris)로부터의 »ksh93둘 다 짧은 옵션의 에일리어스로 긴 옵션을 지원하는 균일한 긴 옵션 구현을 추가했습니다.이 원인이 됩니다.ksh93Bourne Shell를 사용하여 합니다.getopts.

Bourne Shell man 페이지에서 선택한 롱옵션의 예를 다음에 나타냅니다.

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

에 Bourne Shell과 ksh93 모두에서 옵션에일리어스를 사용할 수 있는 기간을 나타냅니다.

최신 Bourne Shell의 man 페이지를 참조하십시오.

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

및 OpenSolaris의 getopt(3)의 man 페이지:

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

마지막으로 getopt(1) man 페이지를 클릭하여 오래된 $*를 확인합니다.

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

나는 멋진 bash 도구를 쓰기 위해 bash 도우미를 써야 한다.

프로젝트 홈: 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:"")

즐기다:)

를 들어, '를 만든다고 가정해 보겠습니다.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

여기에서는 최소한의 코드로 파싱을 실현하고 서브스트링과 함께 eval을 사용하여 하나의 케이스에서 추출할 내용을 정의할 수 있는 getopts를 보여 줍니다.

으로는 ★★★★★★★★★★★★★★.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}를 하는 부분 입니다.---★★★★★★★★★★★★★★★★★★.

구문 분석 옵션을 위해 만든 내용을 공유하고 싶었습니다.제 요구 중 일부는 여기 답변으로 충족되지 않았기 때문에 저는 https://github.com/MihirLuthra/bash_option_parser을 생각해내야 했습니다.

이 기능은 다음을 지원합니다.

  • 서브옵션 해석
  • 옵션의 별칭 이름
  • 옵션 args
  • 변수 args
  • 인쇄 사용 및 오류

.fruit을 사용하다

fruit <fruit-name> ...
   [-e|—-eat|—-chew]
   [-c|--cut <how> <why>]
   <command> [<args>] 

-e가 필요
-c두 합니다.
fruit그 자체에는 적어도1개의 인수가 필요합니다.
<command>, 하다, 하다, 하다 등의 하위 .apple,orangegit이 있습니다.commit,push의 개요)

해석하려면:

parse_options \
    'fruit'                         '1 ...'  \
    '-e'     , '--eat' , '--chew'   '0'      \
    '-c'     , '--cut'              '1 1'    \
    'apple'                         'S'      \
    'orange'                        'S'      \
    ';' \
    "$@"

, 사용방법이 틀렸다면 이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸으면 사용방법이 틀렸을 수도 .option_parser_error_msg음음음같 뭇매하다

retval=$?

if [ $retval -ne 0 ]; then
    # this will manage error messages if
    # insufficient or extra args are supplied

    option_parser_error_msg "$retval"

    # This will print the usage
    print_usage 'fruit'
    exit 1
fi

몇 가지 옵션이 통과되었는지 지금 확인하려면

if [ -n "${OPTIONS[-c]}" ]
then
    echo "-c was passed"

    # args can be accessed in a 2D-array-like format
    echo "Arg1 to -c = ${ARGS[-c,0]}"
    echo "Arg2 to -c = ${ARGS[-c,1]}"

fi

은 「Passing Passing(통과)」에도 실행할 수 있습니다.$shift_count로로 합니다.parse_options_detailedargs를 이동하여 서브옵션의 args에 도달한 후 해석을 시작합니다. 예에서는, 이것을 나타내고 있습니다.

자세한 설명은 readme에 기재되어 있으며 예는 저장소에 기재되어 있습니다.

언급URL : https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash