Estou escrevendo um script que pode escolher um arquivo e imprimir conteúdo específico. Por exemplo,
san#./script.sh
Expected Usage : ./script.sh --file1 --dns
(Aqui ele verifica o arquivo1, procura o nome do DNS e imprime. Basicamente, existem subparâmetros em um parâmetro)
Tentei um único parâmetro/opção conforme abaixo:
options=$@
arguments=($options)
index=0;
for argument in $options
do
index=`expr $index + 1`;
case $argument in
-a | --fun1 ) run_function1 ;;
-b | --fun2 ) run_function2 ;;
-c | --fun3 ) run_function3 ;;
esac
done
exit;
[ ${1} ] || helpinfo
Alguém pode sugerir parâmetros duplos (subopções)?
Opções de alvo esperadas:
./script.sh
OPTIONS : ./script.sh -h
./script --fun1 stackoverflow
microsoft
Google
--fun2 Yahoo
Basicamente, cada função examinará um arquivo. Eu olhei para getopt ou getopts, mas ele não tem a opção long (--long não é possível, em vez disso podemos usar apenas -l). Mas, novamente, não tenho certeza dos subparâmetros. Alguém pode ajudar nisso ? Eu não quero usar getopt
ou getopts
.
Responder1
Esta é uma versão mais conveniente de usar do que a primeira que dei aqui, em particular evita código duplicado para opções longas e curtas equivalentes. Ele deve lidar com tudo o que você quiser para opções: opções curtas ( -q
), opções longas ( --quiet
), opções com argumentos, opções curtas acumuladas ( -qlfinput
em vez de -q -l -f input
), opções longas abreviadas exclusivamente ( --qui
em vez de --quiet
), fim das opções por --
.
A maior parte do código é fixa; você só precisa modificar as partes marcadas.
#!/bin/bash
# Update USAGE (USAGE1, USAGE2, USAGE3 may remain unchanged):
USAGE='Usage: prog [-q|--quiet] [-l|--list] [-f file|--file file] [-Q arg|--query arg] args'
USAGE1='
Ambiguously abbreviated long option:'
USAGE2='
No such option:'
USAGE3='
Missing argument for'
# List all long options here (including leading --):
LONGOPTS=(--quiet --list --file --query)
# List all short options that take an option argument here
# (without separator, without leading -):
SHORTARGOPTS=fQ
while [[ $# -ne 0 ]] ; do
# This part remains unchanged
case $1 in
--) shift ; break ;; ### no more options
-) break ;; ### no more options
-*) ARG=$1 ; shift ;;
*) break ;; ### no more options
esac
# This part remains unchanged
case $ARG in
--*)
FOUND=0
for I in "${LONGOPTS[@]}" ; do
case $I in
"$ARG") FOUND=1 ; OPT=$I ; break ;;
"$ARG"*) (( FOUND++ )) ; OPT=$I ;;
esac
done
case $FOUND in
0) echo "$USAGE$USAGE2 $ARG" 1>&2 ; exit 1 ;;
1) ;;
*) echo "$USAGE$USAGE1 $ARG" 1>&2 ; exit 1 ;;
esac ;;
-["$SHORTARGOPTS"]?*)
OPT=${ARG:0:2}
set dummy "${ARG:2}" "$@"
shift ;;
-?-*)
echo "$USAGE" 1>&2 ; exit 1 ;;
-??*)
OPT=${ARG:0:2}
set dummy -"${ARG:2}" "$@"
shift ;;
-?)
OPT=$ARG ;;
*)
echo "OOPS, this can't happen" 1>&2 ; exit 1 ;;
esac
# Give both short and long form here.
# Note: If the option takes an option argument, it it found in $1.
# Copy the argument somewhere and shift afterwards!
case $OPT in
-q|--quiet) QUIETMODE=yes ;;
-l|--list) LISTMODE=yes ;;
-f|--file) [[ $# -eq 0 ]] && { echo "$USAGE$USAGE3 $OPT" 1>&2 ; exit 1 ; }
FILE=$1 ; shift ;;
-Q|--query) [[ $# -eq 0 ]] && { echo "$USAGE$USAGE3 $OPT" 1>&2 ; exit 1 ; }
QUERYARG=$1 ; shift ;;
*) echo "$USAGE$USAGE2 $OPT" 1>&2 ; exit 1 ;;
esac
done
# Remaining arguments are now in "$@":
echo "QUIETMODE = $QUIETMODE"
echo "LISTMODE = $LISTMODE"
echo "FILE = $FILE"
echo "QUERYARG = $QUERYARG"
echo "REMAINING ARGUMENTS:" "$@"
Responder2
CITAR. Sempre cite. Quando em dúvida; citar. Quando não estiver em dúvida;citar.
Por exemplo: seu teste em $1
,(que nunca é alcançado por causa de exit
), travaria seu script se chamado com, por exemplo ./myscript "file name with spaces"
, .
Quando se trata de looping de argumentos, talvez você possa começar com algo assim:
#!/bin/bash
prnt_help()
{
printf "Usage: %s [OPTION]\n" $(basename "$1")
}
# A simple function only to visualize what gets passed and one of many
# ways to deal with it.
do_list()
{
printf "do_list:\n"
printf "OPT: %s\n" "$@"
printf "My list:\n"
while [[ -n "$1" && "${1:0:1}" != "-" ]]; do
printf "Processing %s\n" "$1"
shift
done
}
main()
{
while [[ -n "$1" ]];do
# This test is not needed, but include it if you find use for it.
if [[ "${1:0:1}" != "-" ]]; then
shift
continue
fi
# Check option and pass rest of arguments to matching function
printf "Checking option %s\n" "$1"
case "$1" in
"-l"|"--list") shift; do_list "$@";;
"-h"|"--help") prnt_help "$0";;
"--") printf "Rest is not options even if starts with -\n"
break;;
esac
shift
done
# If you use "--" to separate out e.g. filenames starting with -
# then process them here.
}
main "$@"
Responder3
Construídas emgetopts
analisa apenas opções curtas (exceto ksh93), mas você ainda pode adicionar algumas linhas de script para fazer com que getopts lide com opções longas.
Aqui está uma parte do código encontrado emhttp://www.uxora.com/unix/shell-script/22-handle-long-options-with-getopts
#== set short options ==#
SCRIPT_OPTS=':fbF:B:-:h'
#== set long options associated with short one ==#
typeset -A ARRAY_OPTS
ARRAY_OPTS=(
[foo]=f
[bar]=b
[foobar]=F
[barfoo]=B
[help]=h
[man]=h
)
#== parse options ==#
while getopts ${SCRIPT_OPTS} OPTION ; do
#== translate long options to short ==#
if [[ "x$OPTION" == "x-" ]]; then
LONG_OPTION=$OPTARG
LONG_OPTARG=$(echo $LONG_OPTION | grep "=" | cut -d'=' -f2)
LONG_OPTIND=-1
[[ "x$LONG_OPTARG" = "x" ]] && LONG_OPTIND=$OPTIND || LONG_OPTION=$(echo $OPTARG | cut -d'=' -f1)
[[ $LONG_OPTIND -ne -1 ]] && eval LONG_OPTARG="\$$LONG_OPTIND"
OPTION=${ARRAY_OPTS[$LONG_OPTION]}
[[ "x$OPTION" = "x" ]] && OPTION="?" OPTARG="-$LONG_OPTION"
if [[ $( echo "${SCRIPT_OPTS}" | grep -c "${OPTION}:" ) -eq 1 ]]; then
if [[ "x${LONG_OPTARG}" = "x" ]] || [[ "${LONG_OPTARG}" = -* ]]; then
OPTION=":" OPTARG="-$LONG_OPTION"
else
OPTARG="$LONG_OPTARG";
if [[ $LONG_OPTIND -ne -1 ]]; then
[[ $OPTIND -le $Optnum ]] && OPTIND=$(( $OPTIND+1 ))
shift $OPTIND
OPTIND=1
fi
fi
fi
fi
#== discard option argument start with hyphen ==#
if [[ "x${OPTION}" != "x:" ]] && [[ "x${OPTION}" != "x?" ]] && [[ "${OPTARG}" = -* ]]; then
OPTARG="$OPTION" OPTION=":"
fi
#== manage options ==#
case "$OPTION" in
f ) foo=1 bar=0 ;;
b ) foo=0 bar=1 ;;
B ) barfoo=${OPTARG} ;;
F ) foobar=1 && foobar_name=${OPTARG} ;;
h ) usagefull && exit 0 ;;
: ) echo "${SCRIPT_NAME}: -$OPTARG: option requires an argument" >&2 && usage >&2 && exit 99 ;;
? ) echo "${SCRIPT_NAME}: -$OPTARG: unknown option" >&2 && usage >&2 && exit 99 ;;
esac
done
shift $((${OPTIND} - 1))
Aqui está um teste:
# Short options test
$ ./foobar_any_getopts.sh -bF "Hello world" -B 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello world
files=file1 file2
# Long and short options test
$ ./foobar_any_getopts.sh --bar -F Hello --barfoo 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello
files=file1 file2
De outra formano recente Korn Shellksh93, getopts
pode naturalmente analisar opções longas e até mesmo exibir uma página de manual semelhante. (verhttp://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options).