[bash] Bash에서 플래그로 인수를 얻는 방법
bash에서 다음과 같은 위치 매개 변수를 쉽게 얻을 수 있다는 것을 알고 있습니다.
$0
또는 $1
다음과 같은 플래그 옵션을 사용하여 각 매개 변수가 사용되는 항목을 지정할 수 있기를 원합니다.
mysql -u user -h host
위치가 아닌 깃발로 -u param
가치와 -h param
가치 를 얻는 가장 좋은 방법은 무엇입니까 ?
답변
이것은 내가 일반적으로 사용하는 관용구입니다.
while test $# -gt 0; do
case "$1" in
-h|--help)
echo "$package - attempt to capture frames"
echo " "
echo "$package [options] application [arguments]"
echo " "
echo "options:"
echo "-h, --help show brief help"
echo "-a, --action=ACTION specify an action to use"
echo "-o, --output-dir=DIR specify a directory to store output in"
exit 0
;;
-a)
shift
if test $# -gt 0; then
export PROCESS=$1
else
echo "no process specified"
exit 1
fi
shift
;;
--action*)
export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'`
shift
;;
-o)
shift
if test $# -gt 0; then
export OUTPUT=$1
else
echo "no output dir specified"
exit 1
fi
shift
;;
--output-dir*)
export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'`
shift
;;
*)
break
;;
esac
done
핵심 사항은 다음과 같습니다.
$#
인수의 수- while 루프는 제공된 모든 인수를보고 case 문 내에서 값과 일치합니다.
- 교대는 첫 번째 것을 빼앗아갑니다. case 문 내에서 여러 번 이동하여 여러 값을 취할 수 있습니다.
답변
이 예제는 Bash의 내장 getopts
명령을 사용하며 Google Shell Style Guide에서 제공됩니다 .
a_flag=''
b_flag=''
files=''
verbose='false'
print_usage() {
printf "Usage: ..."
}
while getopts 'abf:v' flag; do
case "${flag}" in
a) a_flag='true' ;;
b) b_flag='true' ;;
f) files="${OPTARG}" ;;
v) verbose='true' ;;
*) print_usage
exit 1 ;;
esac
done
참고 : 문자 뒤에 콜론 (예 :)이 오는 경우 f:
해당 옵션에 인수가 있어야합니다.
사용법 예 : ./script -v -a -b -f filename
getopts를 사용하면 허용되는 답변보다 몇 가지 장점이 있습니다.
- while 조건은 훨씬 더 읽기 쉽고 허용되는 옵션이 무엇인지 보여줍니다.
- 더 깨끗한 코드; 매개 변수의 수를 세지 않고 이동
- 옵션에 가입 할 수 있습니다 (예 :
-a -b -c
→-abc
)
그러나 큰 단점은 긴 옵션을 지원하지 않고 단일 문자 옵션 만 지원한다는 것입니다.
답변
getopt는 당신의 친구입니다. 간단한 예 :
function f () {
TEMP=`getopt --long -o "u:h:" "$@"`
eval set -- "$TEMP"
while true ; do
case "$1" in
-u )
user=$2
shift 2
;;
-h )
host=$2
shift 2
;;
*)
break
;;
esac
done;
echo "user = $user, host = $host"
}
f -u myself -h some_host
/ usr / bin 디렉토리에는 다양한 예제가 있어야합니다.
답변
나는 이것이 당신이 달성하고자하는 것의 더 간단한 예라고 생각합니다. 외부 도구를 사용할 필요가 없습니다. 내장 된 도구가 작업을 수행 할 수 있습니다.
function DOSOMETHING {
while test $# -gt 0; do
case "$1" in
-first)
shift
first_argument=$1
shift
;;
-last)
shift
last_argument=$1
shift
;;
*)
echo "$1 is not a recognized flag!"
return 1;
;;
esac
done
echo "First argument : $first_argument";
echo "Last argument : $last_argument";
}
이를 통해 플래그를 사용할 수 있으므로 매개 변수를 전달하는 순서에 관계없이 올바른 동작을 얻게됩니다.
예 :
DOSOMETHING -last "Adios" -first "Hola"
출력 :
First argument : Hola
Last argument : Adios
이 기능을 프로필에 추가하거나 스크립트 안에 넣을 수 있습니다.
감사!
편집 : 이것을 파일로 저장하고 다음으로 실행하십시오. yourfile.sh -last "Adios" -first "Hola"
#!/bin/bash
while test $# -gt 0; do
case "$1" in
-first)
shift
first_argument=$1
shift
;;
-last)
shift
last_argument=$1
shift
;;
*)
echo "$1 is not a recognized flag!"
return 1;
;;
esac
done
echo "First argument : $first_argument";
echo "Last argument : $last_argument";
답변
다른 대안은 아래 예제와 같이 long –image 또는 short -i 태그를 사용하고 컴파일 된 -i = “example.jpg” 또는 별도의 -i example.jpg 인수를 전달할 수있는 메소드를 사용하는 것입니다. .
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value)
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";
# $@ here represents all arguments passed in
for i in "$@"
do
arguments[$index]=$i;
prev_index="$(expr $index - 1)";
# this if block does something akin to "where $i contains ="
# "%=*" here strips out everything from the = to the end of the argument leaving only the label
if [[ $i == *"="* ]]
then argument_label=${i%=*}
else argument_label=${arguments[$prev_index]}
fi
# this if block only evaluates to true if the argument label exists in the variables array
if [[ -n ${variables[$argument_label]} ]]
then
# dynamically creating variables names using declare
# "#$argument_label=" here strips out the label leaving only the value
if [[ $i == *"="* ]]
then declare ${variables[$argument_label]}=${i#$argument_label=}
else declare ${variables[$argument_label]}=${arguments[$index]}
fi
fi
index=index+1;
done;
# then you could simply use the variables like so:
echo "$git_user";
답변
Robert McMahan의 답변이 여기에 가장 좋습니다. 모든 스크립트에서 공유 가능한 포함 파일을 만드는 것이 가장 쉬운 것처럼 보입니다. 그러나 if [[ -n ${variables[$argument_label]} ]]
“변수 : 잘못된 배열 아래 첨자”라는 메시지를 표시 하는 줄에 결함이있는 것 같습니다 . 나는 의견에 담당자가없는, 나는이 적절한 의심 ‘수정’하지만 포장 if
의 if [[ -n $argument_label ]] ; then
세척 과정이까지.
더 나은 방법을 알고 있다면 Robert의 답변에 의견을 추가하십시오.
파일 포함 “flags-declares.sh”
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
파일 포함 “flags-arguments.sh”
# $@ here represents all arguments passed in
for i in "$@"
do
arguments[$index]=$i;
prev_index="$(expr $index - 1)";
# this if block does something akin to "where $i contains ="
# "%=*" here strips out everything from the = to the end of the argument leaving only the label
if [[ $i == *"="* ]]
then argument_label=${i%=*}
else argument_label=${arguments[$prev_index]}
fi
if [[ -n $argument_label ]] ; then
# this if block only evaluates to true if the argument label exists in the variables array
if [[ -n ${variables[$argument_label]} ]] ; then
# dynamically creating variables names using declare
# "#$argument_label=" here strips out the label leaving only the value
if [[ $i == *"="* ]]
then declare ${variables[$argument_label]}=${i#$argument_label=}
else declare ${variables[$argument_label]}=${arguments[$index]}
fi
fi
fi
index=index+1;
done;
“script.sh”
. bin/includes/flags-declares.sh
# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value)
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";
. bin/includes/flags-arguments.sh
# then you could simply use the variables like so:
echo "$git_user";
echo "$git_branch";
echo "$db_fqdn";
echo "$environment";
답변
Python argparse에 익숙하고 bash 인수를 구문 분석하기 위해 python을 호출하는 것을 신경 쓰지 않으면 argparse-bash https://github.com/nhoffman/ 이라는 정말 유용하고 사용하기 쉬운 코드가
있습니다. argparse-bash
예제는 example.sh 스크립트에서 가져옵니다.
#!/bin/bash
source $(dirname $0)/argparse.bash || exit 1
argparse "$@" <<EOF || exit 1
parser.add_argument('infile')
parser.add_argument('outfile')
parser.add_argument('-a', '--the-answer', default=42, type=int,
help='Pick a number [default %(default)s]')
parser.add_argument('-d', '--do-the-thing', action='store_true',
default=False, help='store a boolean [default %(default)s]')
parser.add_argument('-m', '--multiple', nargs='+',
help='multiple values allowed')
EOF
echo required infile: "$INFILE"
echo required outfile: "$OUTFILE"
echo the answer: "$THE_ANSWER"
echo -n do the thing?
if [[ $DO_THE_THING ]]; then
echo " yes, do it"
else
echo " no, do not do it"
fi
echo -n "arg with multiple values: "
for a in "${MULTIPLE[@]}"; do
echo -n "[$a] "
done
echo