2012-04-24 26 views
22

Me gustaría definir una abreviatura simple de una llamada a gs (ghostscript) a través de un script de shell. El (los) primer (s) argumento (s) dan todos los archivos que se deben combinar, el último da el nombre del archivo de salida. Obviamente, la siguiente no funciona (es sólo para mostrar la meta):¿Cómo se define un script de shell con una cantidad variable de argumentos?

#!/bin/sh 
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=$last $1 $2 ... 

¿Cómo puede hacerse esto?

Uno normalmente llamaría a este script a través de myscript infile1.pdf infile2.pdf ... outfile.pdf o myscript *.pdf outfile.pdf.

Respuesta

34

Las variables de bash [email protected] y $* se amplían a la lista de argumentos de línea de comando. Generalmente, querrá usar "[email protected]" (es decir, [email protected] rodeado de comillas dobles). Esto hará lo correcto si alguien le pasa a su script un argumento que contenga espacios en blanco.

Así que si usted ha tenido este en el script:

outputfile=$1 
shift 
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=$outputfile "[email protected]" 

Y tuvo que llamar al script como el siguiente:

myscript out.pdf foo.ps bar.ps "another file.ps" 

Esto se expandiría a:

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=out.pdf foo.ps bar.ps "another file.ps" 

Leer el "Special Parameters" sección de la página del manual bash para obtener más información.

+0

Gracias larsks. ¿Es posible tener el nombre del archivo de salida como el argumento * last * (no el primero)? –

+0

Marius Hofert: No puede cambiar fácilmente el último elemento, por lo que es un poco más complicado. Algo como esto: 'outputfile = $ {@: -1}; args = ("$ {@: 1: $ (($ {# @} - 1))}") '. Deberías aceptar la respuesta de este larsks. – jordanm

+0

Usted * puede *, pero es un poco feo. Idelic tiene un ejemplo en su respuesta. Terminas con mucho más cruft en tu código. – larsks

18

Para pasar el archivo de salida como último argumento, utilice una matriz:

ARGS=("[email protected]") 
# Get the last argument 
outputfile=${ARGS[-1]} 
# Drop it from the array 
unset ARGS[${#ARGS[@]}-1] 

exec gs ... -sOUTPUTFILE=$outputfile "${ARGS[@]}" 

Antes de la versión 4, bash no permitió subíndices negativos en matrices (y produjo el error reportado por Marius en los comentarios) , así que si está utilizando 3.x necesita usar el más feo

outputfile=${ARGS[${#ARGS[@]}-1]} 

Esto también funciona para bash 4.x.

+0

I obtenemos: gsMerge infile1.pdf infile2.pdf all.pdf /usr/bin/gsMerge: Línea 4: ARGS: malo subíndice de matriz **** No se puede abrir el dispositivo inicial, dejar de fumar. –

+0

@Marius: Probablemente estés usando una versión anterior de 'bash'. Actualicé la respuesta para cubrir ese caso. – Idelic

+0

Gracias, Idelic, muy bueno. –

7

Para acceder al último argumento, además de la respuesta de Idelic anteriormente, también se puede hacer:

echo "${@: $#}" 

Esto lee todos los argumentos y los imprime a partir de la última. De esta forma, también puede acceder a los últimos N argumentos, por ejemplo, para los últimos tres argumentos:

echo "${@: $#-2}" 

$ ./script "what does" "this script" "do" "?" 
this script do ? 
+0

Guau, esto es increíble. ¿Dónde se define esto en el manual? ¿Y hay una versión de rango de esto? –

+0

Ver esta respuesta: [link] (https://stackoverflow.com/questions/1335815/how-to-slice-an-array-in-bash) sobre el empalme de matrices, la respuesta anterior es simplemente usarlo para cortar el conjunto de argumentos de entrada. –

Cuestiones relacionadas