getopt
y getopts
son diferentes bestias, y las personas parecen tener un poco de incomprensión de lo que hacen. getopts
es un comando incorporado bash
para procesar las opciones de la línea de comandos en un bucle y asignar cada opción y valor encontrados a su vez a las variables incorporadas, para que pueda procesarlas aún más. getopt
, sin embargo, es un programa de utilidad externo, y en realidad no procesa sus opciones para usted de la manera en que lo hacen, por ejemplo getopts
, bash , el Getopt
módulo Perl o Python optparse
/ argparse
modules. Todo lo que getopt
hace es canonizar las opciones que se pasan, es decir, convertirlas a una forma más estándar, para que sea más fácil para un script de shell procesarlas. Por ejemplo, una aplicación de getopt
podría convertir lo siguiente:
myscript -ab infile.txt -ooutfile.txt
dentro de esto:
myscript -a -b -o outfile.txt infile.txt
Tienes que hacer el procesamiento real tú mismo. No tiene que usarlo getopt
en absoluto si establece varias restricciones en la forma en que puede especificar opciones:
- solo pon una opción por argumento;
- todas las opciones van antes que cualquier parámetro posicional (es decir, argumentos sin opciones);
- para opciones con valores (por ejemplo,
-o
arriba), el valor debe ir como un argumento separado (después de un espacio).
¿Por qué usar en getopt
lugar de getopts
? La razón básica es que solo GNU getopt
le brinda soporte para las opciones de línea de comandos de nombre largo. 1 (GNU getopt
es el valor predeterminado en Linux. Mac OS X y FreeBSD vienen con una getopt
versión básica y no muy útil , pero la versión GNU se puede instalar; ver más abajo).
Por ejemplo, aquí hay un ejemplo del uso de GNU getopt
, de un script mío llamado javawrap
:
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
-n 'javawrap' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
case "$1" in
-v | --verbose ) VERBOSE=true; shift ;;
-d | --debug ) DEBUG=true; shift ;;
-m | --memory ) MEMORY="$2"; shift 2 ;;
--debugfile ) DEBUGFILE="$2"; shift 2 ;;
--minheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
--maxheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
Esto le permite especificar opciones como --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
o similar. El efecto de la llamada a getopt
es canonizar las opciones para --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
que pueda procesarlas más fácilmente. La cita alrededor "$1"
y"$2"
es importante ya que garantiza que los argumentos con espacios en ellos se manejen correctamente.
Si elimina las primeras 9 líneas (todo a través de la eval set
línea), ¡el código seguirá funcionando ! Sin embargo, su código será mucho más exigente en el tipo de opciones que acepta: en particular, tendrá que especificar todas las opciones en el formulario "canónico" descrito anteriormente. Sin getopt
embargo, con el uso de , puede agrupar opciones de una sola letra, usar formas más cortas y no ambiguas de opciones largas, usar el estilo --file foo.txt
o --file=foo.txt
, usar el estilo -m 4096
o -m4096
, mezclar opciones y no opciones en cualquier orden, etc. getopt
también genera un mensaje de error si se encuentran opciones no reconocidas o ambiguas.
NOTA : En realidad, hay dos versiones totalmente diferentes de getopt
, basic getopt
y GNU getopt
, con diferentes características y diferentes convenciones de llamadas. 2 Basic getopt
está bastante roto: no solo no maneja opciones largas, sino que ni siquiera puede manejar espacios incrustados dentro de argumentos o argumentos vacíos, mientras getopts
que lo hace bien. El código anterior no funcionará en básico getopt
. GNU getopt
se instala por defecto en Linux, pero en Mac OS X y FreeBSD necesita instalarse por separado. En Mac OS X, instale MacPorts ( http://www.macports.org ) y luego sudo port install getopt
instale GNU getopt
(generalmente en /opt/local/bin
), y asegúrese de que /opt/local/bin
esté en su ruta de shell antes de/usr/bin
. En FreeBSD, instalemisc/getopt
.
Una guía rápida para modificar el código de ejemplo para su propio programa: de las primeras líneas, todas son "repetitivas" que deben permanecer igual, excepto la línea que llama getopt
. Debe cambiar el nombre del programa después -n
, especificar opciones cortas después -o
y opciones largas después --long
. Poner dos puntos después de las opciones que toman un valor.
Finalmente, si ve un código que tiene solo en set
lugar de eval set
, fue escrito para BSD getopt
. Debe cambiarlo para usar el eval set
estilo, que funciona bien con ambas versiones de getopt
, mientras que el plano set
no funciona bien con GNU getopt
.
1 En realidad, getopts
en ksh93
soportes opciones nombrado largo, pero esta capa no se utiliza tan a menudo como bash
. En zsh
, use zparseopts
para obtener esta funcionalidad.
2 Técnicamente, "GNU getopt
" es un nombre inapropiado; Esta versión fue escrita para Linux en lugar del proyecto GNU. Sin embargo, sigue todas las convenciones de GNU, y el término "GNU getopt
" se usa comúnmente (por ejemplo, en FreeBSD).