etc./StackOverFlow

Bash에서 명령줄 인수를 어떻게 구문 분석합니까?

청렴결백한 만능 재주꾼 2021. 12. 3. 08:21
반응형

질문자 :Lawrence Johnston


다음 줄로 호출되는 스크립트가 있습니다.

 ./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 과 같도록 이것을 구문 분석하는 허용되는 방법은 무엇입니까?



Bash 공백으로 구분(예: --option argument )

 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
용법
 demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts

Bash 등호로 --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 ;; -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
용법
 demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts

${i#*=} 를 더 잘 이해하려면 이 가이드 에서 "하위 문자열 제거"를 검색하십시오. 이는 불필요한 하위 프로세스 또는 `echo "$i" | sed 's/[^=]*=//'` `sed 's/[^=]*=//' <<< "$i"` 와 기능적으로 동일합니다. `echo "$i" | sed 's/[^=]*=//'` 두 개의 불필요한 하위 프로세스를 호출합니다.


getopt와 함께 bash 사용하기

getopt(1) 제한 사항(이전의 비교적 최근 getopt 버전):

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

최신 getopt 버전에는 이러한 제한이 없습니다. 자세한 내용은 이 문서를 참조하십시오.


POSIX getopts

또한, POSIX 쉘 등이 제공 getopts 이러한 제한이 doen't. getopts 예제를 포함했습니다.

 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. 일반적인 Unix 방식으로 -vf filename 과 같은 여러 단일 옵션을 자동으로 처리할 수 있습니다.

getopts 의 단점은 추가 코드 없이 -h , --help 아님)만 처리할 수 있다는 것입니다.

모든 구문과 변수가 의미하는 바를 설명하는 getopts 튜토리얼이 있습니다. bash에는 정보를 제공할 수 있는 help getopts


Bruno Bronosky

답변 없음은 향상된 getopt를 보여줍니다. 그리고 가장 많이 득표한 답변 은 오해의 소지가 있습니다. -⁠vfd 스타일의 짧은 옵션(OP에서 요청함) 또는 위치 인수 뒤의 옵션(OP에서도 요청함)을 무시합니다. 구문 분석 오류를 무시합니다. 대신에:

  • util-linux 또는 이전 GNU glibc에서 향상된 getopt 를 사용합니다. 1
  • GNU glibc의 getopt_long() C 함수와 함께 작동합니다.
  • 이 페이지의 다른 솔루션은 이 모든 작업을 수행할 수 없습니다 .
    • 공백, 인용 문자 및 인수 2의 바이너리도 처리합니다(비향상된 getopt 는 이 작업을 수행할 수 없음).
    • 마지막에 옵션을 처리할 수 있습니다: script.sh -o outFile file1 file2 -v ( getopts 는 이것을 하지 않습니다)
    • 허용 = -style 긴 옵션: script.sh --outfile=fileOut --infile fileIn (자체 구문 분석의 경우 둘 다 허용하는 것은 길다)
    • -vfd (자체 구문 분석의 경우 실제 작업)와 같은 짧은 옵션을 결합할 수 있습니다.
    • -oOutfile 수 있습니다(예: -oOutfile 또는 -vfdoOutfile
  • (어떤 리눅스를 가지고 예)에는 GNU 시스템이 누락되지 않도록 3 이미 오래되었습니다.
  • getopt --test → return value 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 # More safety, by turning some bugs into errors. # Without `errexit` you don't need ! and can replace # PIPESTATUS with a simple $?, but I don't do that. 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 (eg 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 # eg 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=nf=nv=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 POSIX exec() 규칙에는 명령줄 인수에서 이진 NULL을 전달하는 신뢰할 수 있는 방법이 없습니다. 해당 바이트는 인수를 조기에 종료합니다.
3 1997년 또는 그 이전에 출시된 첫 번째 버전(1997년까지만 추적했습니다)


Robert Siemer

배포.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

Inanc Gumus

약간 수정한 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#*=} 를 더 잘 이해하려면 이 가이드 에서 "하위 문자열 제거"를 검색하십시오. 이는 불필요한 하위 프로세스 또는 `echo "$i" | sed 's/[^=]*=//'` `sed 's/[^=]*=//' <<< "$i"` 와 기능적으로 동일합니다. `echo "$i" | sed 's/[^=]*=//'` 두 개의 불필요한 하위 프로세스를 호출합니다.


guneysus

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을 사용하지 않음
  • 읽기 가능하며 루프에서 상태를 유지할 필요가 없습니다.

bronson

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"는 옵션을 분리하고 각각을 자체 인수에 넣습니다. 또한 "--"를 추가했습니다.


Matt J

이전 임시 매개변수 구문 분석을 정리하기 위한 시작점으로 이전 답변을 사용했습니다. 그런 다음 다음 템플릿 코드를 리팩토링했습니다. = 또는 공백으로 구분된 인수와 함께 그룹화된 여러 개의 짧은 매개변수를 사용하여 긴 매개변수와 짧은 매개변수를 모두 처리합니다. 마지막으로 매개변수가 아닌 인수를 $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

Shane Day

스크립트에 이식 가능한 구문 분석을 작성하는 문제를 발견하여 Argbash를 작성했습니다. Argbash - 스크립트에 대한 인수 구문 분석 코드를 생성할 수 있는 FOSS 코드 생성기이며 여기에는 몇 가지 멋진 기능이 있습니다.

https://argbash.io


bubla

# 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=value 및 -arg 값 모두 허용

  • bash에서 사용할 수 있는 모든 인수 이름과 함께 작동합니다.

    • 의미 -a 또는 -arg 또는 --arg 또는 -arg 또는 무엇이든
  • 순수한 배쉬. getopt 또는 getopts를 배우거나 사용할 필요가 없습니다.

단점:

  • 인수를 결합할 수 없음

    • 의미 없음 -abc. -a -b -c를 수행해야 합니다.

Ponyboy47

getoptevalHEREDOCshift 를 사용하여 뒤에 오는 필수 값이 있거나 없는 short 및 long 매개변수를 처리하는 방법을 보여줍니다. 또한 switch/case 문은 간결하고 따르기 쉽습니다.

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

그것이 누군가를 돕기를 바랍니다.


phyatt

다른 유틸리티와 호환되는 스크립트를 만드는 경우 아래의 유연성이 유용할 수 있습니다.

어느 하나:

 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

unsynchronized

@bruno-bronosky의 답변을 확장하여 몇 가지 일반적인 형식을 처리하기 위해 "전처리기"를 추가했습니다.

  • --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") ;; -*) 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[@]}"

jchook

나는 이것이 사용하기에 충분히 간단하다고 생각합니다.

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

Alek

명령줄에서 매개변수를 구문 분석하는 parse_params 함수를 제공합니다.

  1. 추가 유틸리티가 없는 순수한 Bash 솔루션입니다.
  2. 전역 범위를 오염시키지 않습니다.
  3. 추가 논리를 구축할 수 있는 사용하기 쉬운 변수를 손쉽게 반환합니다.
  4. params 앞의 대시 수는 중요하지 않습니다( --all equals -all equals 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

Oleksii Chekulaiev

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

vangorra

또 다른 옵션 파서(생성기)

셸 스크립트를 위한 우아한 옵션 파서(모든 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 셸(dash 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

또한 옵션 파서 생성기이며 다음과 같은 간단한 옵션 파싱 코드를 생성합니다. 생성된 코드를 사용하는 경우 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 }

Koichi Nakashima

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

 source argparser.sh parse_args "$@"

간단합니다. 환경은 인수와 이름이 같은 변수로 채워집니다.


Thanh Trung

이것은 스택에서 더 높은 곳에서 동시에 실행되는 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 ... }

akostadinov

다음을 허용하는 내 버전의 옵션 구문 분석을 제공하고 싶습니다.

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

또한 이것을 허용합니다(원치 않을 수 있음).

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

옵션에 =를 사용할지 여부를 사용하기 전에 결정해야 합니다. 이것은 코드를 깨끗하게(ish) 유지하기 위한 것입니다.

 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

galmok

cmdline 인수를 구문 분석하는 방법에는 여러 가지가 있습니다(예: GNU getopt(이동 불가능) vs BSD(MacOS) getopt vs getopts) - 모두 문제가 있습니다. 이 솔루션

  • 휴대용입니다!
  • 종속성이 없으며 bash 내장 기능에만 의존합니다.
  • 짧은 옵션과 긴 옵션 모두 허용
  • 공백을 처리하거나 옵션과 인수 사이 =
  • 연결된 짧은 옵션 스타일 지원 -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=${@}"

tmoschou

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

여기 내 솔루션이 있습니다. 매우 유연하고 다른 것과 달리 외부 패키지가 필요하지 않으며 남은 인수를 깔끔하게 처리합니다.

사용법은 다음과 같습니다. ./myscript -flag flagvariable -otherflag flagvar2

validflags 행을 편집하기만 하면 됩니다. 하이픈을 추가하고 모든 인수를 검색합니다. 그런 다음 플래그 이름으로 다음 인수를 정의합니다.

 ./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는 단일 인수로 처리됨). 그래도 이 기능을 추가하는 추가 코드를 광산에 쉽게 작성할 수 있습니다.


user6768257

getopt(1) 는 AT&T의 짧은 실수였습니다.

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

getopt 가 매우 구식이라는 사실에 대한 증거 getopt(1) 매뉴얼 페이지 getopts(1) 쉘 내장과 함께 Bourne 쉘에 추가된 "$@" 대신 "$*" 내부에 공백이 있는 인수를 처리하기 위해.

BTW: 셸 스크립트에서 긴 옵션을 구문 분석하는 데 관심이 있는 경우 libc(Solaris) 및 ksh93 getopt(3) 구현이 모두 긴 옵션을 짧은 별칭으로 지원하는 균일한 긴 옵션 구현을 추가했다는 사실을 아는 것이 흥미로울 수 있습니다. 옵션. 이로 인해 ksh93Bourne Shell getopts 를 통해 긴 옵션에 대해 균일한 인터페이스를 구현합니다.

Bourne Shell 매뉴얼 페이지에서 가져온 긴 옵션의 예:

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

Bourne Shell과 ksh93에서 옵션 별칭을 사용할 수 있는 기간을 보여줍니다.

최근 Bourne Shell의 매뉴얼 페이지를 참조하십시오.

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

OpenSolaris의 getopt(3) 매뉴얼 페이지:

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

마지막으로 getopt(1) 매뉴얼 페이지에서 오래된 $*를 확인합니다.

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


schily

@bronson의 비교적 간단한 답변에 영감을 받아 (복잡성을 너무 많이 추가하지 않고) 개선하려고 했습니다. 결과는 다음과 같습니다.

ASAP(또 다른 Shell Argument Parser) – POSIX, getopt*

  • -n [arg] , -abn [arg] , --name [arg] --name=arg 스타일의 옵션을 사용하십시오.
  • 인수는 순서에 관계없이 발생할 수 있으며 루프 후 $@ 에는 위치 인수만 남습니다.
  • -- 를 사용 하여 나머지 인수를 위치 지정으로 처리 하도록 강제합니다.
  • 잘못된 옵션과 누락된 인수를 감지합니다.
  • getopt(s) 또는 외부 도구에 의존하지 않습니다(한 기능은 간단한 sed 명령을 사용함).
  • 독립적인 기능 과 함께 휴대 가능하고 컴팩트하며 읽기 쉽습니다.
 # Convenience functions. usage_error () { echo >&2 "$(basename $0): $1"; exit 2; } assert_argument () { test "$1" != "$EOL" || usage_error "$2 requires an argument"; } # One loop, nothing more. EOL=$(echo '\01\03\03\07') if [ "$#" != 0 ]; then set -- "$@" "$EOL" while [ "$1" != "$EOL" ]; do opt="$1"; shift case "$opt" in # Your options go here. -f|--flag) flag=true;; -n|--name) assert_argument "$1" $opt; name="$1"; shift;; -|''|[^-]*) set -- "$@" "$opt";; # positional argument, rotate to the end # Extra features (you may remove any line you don't need): --*=*) set -- "${opt%%=*}" "${opt#*=}" "$@";; # convert '--name=arg' to '--name' 'arg' -[^-]?*) set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@";; # convert '-abc' to '-a' '-b' '-c' --) while [ "$1" != "$EOL" ]; do set -- "$@" "$1"; shift; done;; # process remaining arguments as positional -*) usage_error "unknown option: '$opt'";; # catch misspelled options *) usage_error "this should NEVER happen ($opt)";; # sanity test for previous patterns esac done shift # $EOL fi # Do something cool with "$@"... \o/

참고: 알아요... 바이너리 패턴이 0x01030307 인 인수는 논리를 깨뜨릴 수 있습니다. 그러나 누군가가 명령줄에서 그러한 인수를 전달한다면 그들은 그럴 자격이 있습니다.


leogama

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

--param=arg(같음으로 구분됨)

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

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

--param 인수(공백으로 구분)

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

Mark Fox

좋은 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 -of -d "First name" -t string -i -s -r bashopts_declare -n last_name -l last -ol -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:"")

즐겨 :)


Emeric Verschuur

여기 내 접근 방식이 있습니다 - regexp를 사용합니다.

  • 아니 getopts
  • 짧은 매개변수 블록 처리 -qwerty
  • 짧은 매개변수를 처리합니다. -q -w -e
  • --qwerty 처리합니다.
  • 속성을 short 또는 long 옵션에 전달할 수 있습니다(짧은 옵션 블록을 사용하는 경우 속성은 마지막 옵션에 첨부됨)
  • 공백 또는 = 를 사용하여 속성을 제공할 수 있지만 하이픈+공백 "구분자"가 나타날 때까지 속성이 일치하므로 --q=qwe ty qwe ty 는 하나의 속성입니다.
  • 위의 모든 것을 혼합하여 처리하므로 -oa -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

a_z

다음과 같이 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

John

파싱 옵션을 위해 만든 것을 공유하고 싶었습니다. 내 요구 사항 중 일부는 여기에 있는 답변으로 충족되지 않았으므로 다음과 같이 제안해야 했습니다. https://github.com/MihirLuthra/bash_option_parser

이것은 다음을 지원합니다.

  • 하위 옵션 구문 분석
  • 옵션의 별칭 이름
  • 선택적 인수
  • 변수 인수
  • 인쇄 사용 및 오류

다음과 같이 사용되는 fruit 이라는 명령이 있다고 가정해 보겠습니다.

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

-e 는 인수를 사용하지 않습니다.
-c 는 두 개의 인수, 즉 자르는 방법과 자르는 이유를 취합니다.
fruit 자체는 적어도 하나의 인수를 취합니다.
<command> apple , orange 등과 같은 하위 옵션을 위한 것입니다. (하위 옵션이 commit , push 등인 git

그래서 그것을 구문 분석하려면 :

 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

$shift_countparse_options_detailed 에 전달하여 수행할 수도 있습니다. 그러면 하위 옵션의 인수에 도달하기 위해 인수를 이동한 후 구문 분석이 시작됩니다. 이 예 에서 설명됩니다.

자세한 설명은 리포지토리 의 readme 및 예제에서 제공됩니다.


Mihir Luthra

bash-modules 에서 모듈 "인수" 사용

예시:

 #!/bin/bash . import.sh log arguments NAME="world" parse_arguments "-n|--name)NAME;S" -- "$@" || { error "Cannot parse command line." exit 1 } info "Hello, $NAME!"

Volodymyr M. Lisivka

다음은 최소한의 코드로 구문 분석을 수행하고 하위 문자열과 함께 eval을 사용하여 한 경우에 추출하려는 것을 정의할 수 있는 getopt입니다.

기본적으로 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}은 기본적으로 키에서 ---


mmm

출처 : http:www.stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash

반응형