현재 다음과 같은 위치 매개변수와 함께 사용하는 스크립트가 있습니다.
./script.sh fname lname address
또한 제공하고 싶지 않은 인수를 건너뛸 수 있도록 이 스크립트를 호출할 때 일반 명령줄 옵션을 지원하고 싶습니다.
./script.sh -f fname -a address
fname
유일한 필수 매개변수입니다.
역사적 이유와 자동화로 인해 스크립트는 이전 버전과 호환되어야 합니다.
-f
지금까지 내 추측으로는 문자열(공백으로 둘러싸여 있음)을 찾는 것입니다 .
- 발견되면 플래그를 처리합니다.
- 그렇지 않은 경우 순차적으로 처리
flags='(\ |^)-f\ '
if [[ $* =~ $flags ]]; then
while [ $# -ne 0 ]
do
name="$1"
case "$name" in
-f)
shift
fname=$1
;;
-l)
shift
lname=$1
;;
-a)
shift
address=$1
;;
esac
shift
done
else
fname=${1}
lname=${2}
address=${3}
fi
하지만 여기서는 정규식을 사용하여 옵션을 확인해야 하는데 이는 신뢰할 수 없을 수 있습니다.
명령줄 옵션과 위치 매개변수를 결합하는 기본 방법이 있습니까?
답변1
일반적인 명령줄 구문 분석을 구현하는 데 사용됩니다 getopts
. 이 구문 분석이 트리거되면 이 사실을 추적하기 위한 플래그를 설정하십시오. 표준 getopts
루프 후에 플래그가 설정되지 않은 경우 이전 동작이 반환됩니다.
아래 코드에서 플래그는 변수입니다 new_behavior
.
#!/bin/bash
# As written now, this should run without issues with
# /bin/sh too (there are no bash-isms in this code).
unset address
unset fname
unset lname
new_behavior=false
while getopts 'a:f:l:' opt; do
new_behavior=true
case $opt in
a)
address=$OPTARG
;;
f)
fname=$OPTARG
;;
l)
lname=$OPTARG
;;
*)
echo 'Error in command line parsing' >&2
exit 1
esac
done
shift "$(( OPTIND - 1 ))"
if ! "$new_behavior"; then
# Fall back on old behavior.
fname=$1; shift
lname=$1; shift
address=$1; shift
fi
if [ -z "$fname" ]; then
echo 'Missing mandatory argument "fname"' >&2
exit 1
fi
# The rest is unimportant to the actual command line parsing code
# and only here for your information and for debugging.
printf 'fname="%s", lname="%s", address="%s"\n' \
"$fname" "$lname" "$address"
if [ "$#" -gt 0 ]; then
printf 'Extra argument: "%s"\n' "$@"
fi
사용자가 스크립트의 첫 번째 인수로 옵션을 제공하면 새로운 동작이 트리거됩니다. 옵션이 유효한지 여부는 중요하지 않습니다.
이전 동작 테스트:
$ ./script eff ell addr
fname="eff", lname="ell", address="addr"
$ ./script eff ell addr "hello world"
fname="eff", lname="ell", address="addr"
Extra argument: "hello world"
$ ./script eff
fname="eff", lname="", address=""
$ ./script
Missing mandatory argument "fname"
$ ./script eff -l ell
fname="eff", lname="-l", address="ell"
새로운 동작을 테스트합니다.
$ ./script -a addr -l ell -f eff
fname="eff", lname="ell", address="addr"
$ ./script -a addr -f eff "hello world"
fname="eff", lname="", address="addr"
Extra argument: "hello world"
$ ./script -f eff "hello world"
fname="eff", lname="", address=""
Extra argument: "hello world"
$ ./script -l eff "hello world"
Missing mandatory argument "fname"
$ ./script -f eff -- -l ell -f "eff again"
fname="eff", lname="", address=""
Extra argument: "-l"
Extra argument: "ell"
Extra argument: "-f"
Extra argument: "eff again"
(마지막 예에서 옵션이 아닌 추가 인수는 options 와 분리되어 있으며 --
두 -l
번째 인수는 모두 -f
옵션이 아닙니다.)
답변2
그럼 왜 사용해야 할까요 if
? 매개변수를 확인하면 됩니다.
flaggiven=0
# This is very unsafe - use `getopt` or `getopts`. `shift` can fail - should be checked for errors.
while (($#)); do
case "$1" in
-f) fname=$2; flaggiven=1; shift; ;;
-l) lname=$2; flaggiven=1; shift; ;;
-a) address=$2; flaggiven=1; shift; ;;
*) break;
esac
shift
done
if (($# > 0)); then
if ((flaggiven)); then
echo "ERROR: you have given -f or -l or -a argument and arguments. One or the other, not both!"
exit 1
fi
fname=$1
lname=$2
address=$3
else
if ((!flaggiven)); then
echo "ERROR: you have to pass -f -l -a flags or pass 3 arguments"
exit 1
fi
fi