Estoy escribiendo un script que puede elegir un archivo e imprimir contenido específico. Por ejemplo,
san#./script.sh
Expected Usage : ./script.sh --file1 --dns
(Aquí busca el archivo1, busca el nombre dns e imprime. Básicamente, hay subparámetros debajo de un parámetro)
Probé con un solo parámetro/opción como se muestra a continuación:
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
¿Alguien puede sugerir un parámetro doble (subopciones)?
Opciones de destino esperadas:
./script.sh
OPTIONS : ./script.sh -h
./script --fun1 stackoverflow
microsoft
Google
--fun2 Yahoo
Básicamente, cada función buscará en un archivo. He investigado getopt o getopts, pero no tiene la opción larga (--long no es posible, en su lugar solo podemos usar -l). Pero nuevamente no estoy seguro de los subparámetros. Alguien puede ayudarme en esto ? No quiero usar getopt
o getopts
.
Respuesta1
Esta es una versión que es más cómoda de usar que la primera que proporcioné aquí, en particular evita el código duplicado para opciones largas y cortas equivalentes. Debería manejar todo lo que desee para las opciones: opciones cortas ( -q
), opciones largas ( --quiet
), opciones con argumentos, opciones cortas acumuladas ( -qlfinput
en lugar de -q -l -f input
), opciones largas abreviadas de forma única ( --qui
en lugar de --quiet
), fin de opciones por --
.
La mayor parte del código es fijo; sólo tienes que modificar las 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:" "$@"
Respuesta2
CITA. Cita siempre. En caso de duda; cita. Cuando no haya dudas;cita.
Por ejemplo: tu prueba el $1
,(que nunca se alcanza debido a exit
), bloquearía su secuencia de comandos si se llama con, por ejemplo ./myscript "file name with spaces"
, .
Cuando se trata de bucles de argumentos, quizás podrías comenzar con algo como esto:
#!/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 "$@"
Respuesta3
Incorporadogetopts
solo analiza opciones cortas (excepto ksh93), pero aún puede agregar algunas líneas de secuencias de comandos para que getopts maneje opciones largas.
Aquí hay una parte del código que se encuentra enhttp://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))
Aquí hay una prueba:
# 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 lo contrarioen Korn Shell recienteksh93, getopts
puede analizar naturalmente opciones largas e incluso mostrar una página de manual similar. (verhttp://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options).