Jak uzyskać argumenty z flagami w Bash
Wiem, że mogę łatwo uzyskać takie parametry w bash:
$0
lub $1
Chcę być w stanie użyć opcji znaczników takich jak ta, aby określić, do czego każdy parametr jest używany:
mysql -u user -h host
Jaki jest najlepszy sposób na uzyskanie -u param
wartości i -h param
wartości według flagi zamiast według pozycji?
7 answers
To jest idiom, którego zwykle używam:
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
Kluczowe punkty to:
-
$#
jest liczbą argumentów - while loop patrzy na wszystkie podane argumenty, dopasowując ich wartości wewnątrz instrukcji case
- shift zabiera pierwszą. Wewnątrz instrukcji case można przesuwać wiele razy, aby przyjąć wiele wartości.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 01:34:56
Ten przykład wykorzystuje wbudowany Bash getopts
polecenie i pochodzi z 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
Uwaga: Jeśli po znaku następuje dwukropek (np. f:
), Opcja ta powinna mieć argument.
Przykładowe użycie: ./script -v -a -b -f filename
Korzystanie z getopts ma kilka zalet w stosunku do zaakceptowanej odpowiedzi:
- warunek while jest o wiele bardziej czytelny i pokazuje jakie są akceptowane opcje
- cleaner code; no zliczanie liczby parametrów i przesunięcie
- możesz dołączyć opcje (np.
-a -b -c
→-abc
)
Jednak dużą wadą jest to, że nie obsługuje długich opcji, tylko opcje jednoznakowe.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-09 09:17:04
Getopt jest twoim przyjacielem.. prosty przykład:
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
W katalogu /usr/bin powinny być różne przykłady.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-15 20:06:23
Myślę, że posłużyłoby to jako prostszy przykład tego, co chcesz osiągnąć. Nie ma potrzeby korzystania z narzędzi zewnętrznych. Wbudowane narzędzia Bash mogą wykonać zadanie za Ciebie.
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";
}
To pozwoli Ci używać FLAG, więc bez względu na kolejność przekazywania parametrów otrzymasz odpowiednie zachowanie.
Przykład:
DOSOMETHING -last "Adios" -first "Hola"
Wyjście:
First argument : Hola
Last argument : Adios
Możesz dodać tę funkcję do swojego profilu lub umieścić ją wewnątrz skryptu.
Dzięki!Edytuj :
Zapisz to jako a plik a, a następnie wykonaj go jako 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";
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 13:31:52
Inną alternatywą byłoby użycie czegoś takiego jak Poniższy przykład, który pozwoliłby na użycie długich --image lub krótkich -i oraz pozwala na skompilowanie -i="przykład.jpg" lub oddzielny - i przykład.jpg metody przekazywania argumentów.
# 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";
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-10 19:18:58
Najbardziej podoba mi się odpowiedź Roberta McMahona, ponieważ wydaje się, że najłatwiej jest przekształcić je w pliki nagłówkowe, których można użyć w dowolnym skrypcie. Ale wydaje się, że ma wadę z linią if [[ -n ${variables[$argument_label]} ]]
rzucającą komunikat "variables: bad array subscript". Nie mam rep do komentowania, i wątpię, że to jest właściwa "poprawka", ale owinięcie tego if
w if [[ -n $argument_label ]] ; then
czyści to.
Oto kod, z którym skończyłem, jeśli znasz lepszy sposób, dodaj komentarz do odpowiedzi Roberta.
Include Plik "flags-declares.sh"
# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();
# declaring an index integer
declare -i index=1;
Dołącz plik "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;
Twój "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";
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-01 23:00:39
Jeśli jesteś zaznajomiony z Pythonem argparse i nie masz nic przeciwko wywołaniu Pythona do analizy argumentów Basha, istnieje fragment kodu, który uważam za bardzo pomocny i bardzo łatwy w użyciu o nazwie argparse-bash https://github.com/nhoffman/argparse-bash
Przykład wziąć z ich example.sh skrypt:
#!/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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-04 18:37:11