이 줄로 호출되는 스크립트가 있다고 가정 해보십시오.
./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 : getopt [s]없이 bash 사용
키-값 쌍 인수를 전달하는 두 가지 일반적인 방법은 다음과 같습니다.
Bash Space-Separated (예 --option argument
🙂 (getopt없이)
용법 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
Bash Equals-Separated (예 --option=argument
🙂 (getopt [s]없이)
용법 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와 함께 bash 사용하기
에서 : http://mywiki.wooledge.org/BashFAQ/035#getopts
getopt (1) 제한 사항 (이전의 비교적 최신 getopt
버전) :
- 빈 문자열 인 인수를 처리 할 수 없습니다
- 공백이 포함 된 인수를 처리 할 수 없습니다
최신 getopt
버전에는 이러한 제한이 없습니다.
또한 POSIX 셸 (및 기타) 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
은 다음 과 같습니다.
- 이식성이 뛰어나고 다른 쉘에서 작동
dash
합니다. -vf filename
일반적인 Unix 방식 과 같은 여러 단일 옵션을 자동으로 처리 할 수 있습니다 .
의 단점은 getopts
단지 짧은 옵션 (처리 할 수있다 -h
, 없다 --help
추가 코드없이)를.
모든 구문과 변수의 의미를 설명 하는 getopts 학습서 가 있습니다. bash에는 또한 help getopts
유익한 정보가 있습니다.
답변
향상된 getopt에 대한 답변은 없습니다 . 그리고 최고 투표 답변 은 오해의 소지가 있습니다 : 그것은 -vfd
스타일 짧은 옵션 (OP에 의해 요청 된) 또는 위치 인수 후의 옵션 (OP에 의해 요청 된)을 무시합니다 . 파싱 오류를 무시합니다. 대신 :
getopt
util-linux 또는 이전 GNU glibc에서 향상된 기능 을 사용하십시오 . 1getopt_long()
GNU glibc의 C 기능 과 함께 작동합니다 .- 유용한 구별 기능 이 모두 있습니다 (다른 기능은 없음).
- 인수 2 에서 공백, 인용 문자 및 심지어 2 진을 처리합니다 (향상
getopt
되지 않음) - 마지막에 옵션을 처리 할 수 있습니다 :
script.sh -o outFile file1 file2 -v
(getopts
하지 않습니다) - 수 있습니다
=
스타일의 긴 옵션 :script.sh --outfile=fileOut --infile fileIn
(모두를 허용하는 것은 자기 분석하면 긴하다) - 결합 된 짧은 옵션 허용
-vfd
( 예 : 자체 구문 분석의 경우 실제 작업) - 옵션 인수를 터치 할 수 있습니다. 예 :
-oOutfile
또는-vfdoOutfile
- 인수 2 에서 공백, 인용 문자 및 심지어 2 진을 처리합니다 (향상
- 아직 나이가 3 (리눅스가있다 예를 들어)에는 GNU 시스템이 누락되지 않도록.
- 다음과 같이 존재 여부를 테스트 할 수 있습니다.
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"
Cygwin을 포함한 대부분의 “bash-systems”에서 1 개의 향상된 getopt를 사용할 수 있습니다. OS X에서 brew install gnu-getopt 또는sudo port install getopt
2를 시도하십시오. POSIXexec()
규칙은 명령 행 인수에서 2 진 NULL을 전달하는 확실한 방법이 없습니다. 그 바이트는 1997 년 또는 그 이전에 발표 된인수
3 첫 번째 버전을조기에 종료합니다(1997 년까지만 추적했습니다)
답변
간결한 방법
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
답변
에서 : 약간 수정 한 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"`
`echo "$i" | sed 's/[^=]*=//'`
답변
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”는 옵션을 분리하고 각각의 인수에 넣습니다. “-“도 추가되었습니다.
답변
무시할 다른 예를 추가 할 위험이 있으므로 여기 내 계획이 있습니다.
- 손잡이
-n arg
와--name=arg
- 끝에 인수를 허용
- 맞춤법이 틀린 경우 제정신 오류 표시
- 호환 가능, bashism을 사용하지 않음
- 읽을 수 있고 루프에서 상태를 유지할 필요가 없습니다.
누군가에게 유용하기를 바랍니다.
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 년 늦었지만 포기하고 싶습니다. 이전 답변을 이전의 임시 매개 변수 구문 분석을 정리하기위한 출발점으로 사용했습니다. 그런 다음 다음 템플릿 코드를 리팩터링했습니다. = 또는 공백으로 구분 된 인수와 함께 여러 개의 짧은 매개 변수를 함께 사용하여 long 및 short 매개 변수를 처리합니다. 마지막으로 매개 변수가 아닌 인수를 $ 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