2012-04-24 15 views
22

Vorrei definire una semplice abbreviazione di una chiamata a gs (ghostscript) tramite uno script di shell. Il primo argomento (s) fornisce tutti i file che dovrebbero essere uniti, l'ultimo dà il nome del file di output. Ovviamente, quanto segue non funziona (è solo per mostrare l'obiettivo):Come definire uno script di shell con numero variabile di argomenti?

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

Come si può fare?

Uno chiamerebbe in genere questo script tramite myscript infile1.pdf infile2.pdf ... outfile.pdf o myscript *.pdf outfile.pdf.

risposta

34

Le variabili di bash [email protected] e $* si espandono nell'elenco di argomenti della riga di comando. In genere, si desidera utilizzare "[email protected]" (ovvero, [email protected] circondato da virgolette). Questo farà la cosa giusta se qualcuno passa il tuo script un argomento contenente spazi bianchi.

Quindi, se avete avuto questo nello script:

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

E hai chiamato il tuo script come questo:

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

Ciò si espanderebbe a:

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

Leggi il "Special Parameters" sezione della pagina man bash per ulteriori informazioni.

+0

Grazie larsk. È possibile avere il nome del file di output come argomento * last * (non il primo)? –

+0

Marius Hofert: Non puoi spostare facilmente l'ultimo elemento, quindi è un po 'più complicato. Qualcosa del genere: 'outputfile = $ {@: -1}; args = ("$ {@: 1: $ (($ {# @} - 1))}") '. Dovresti accettare la risposta di questo larsk. – jordanm

+0

Si * può *, ma è un po 'brutto. Idelic ha un esempio nella sua risposta. Si finisce con molto più cruft nel codice. – larsks

18

per passare il file di output come ultimo argomento, usare un array:

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

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

Prima della versione 4, bash non hanno permesso indici negativi in ​​array (e prodotto l'errore segnalato da Marius nei commenti) , quindi se si utilizza 3.x è necessario utilizzare il molto più brutto

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

Questo funziona anche per bash 4.x.

+0

Ottiene: gsMerge infile1.pdf infile2.pdf all.pdf /usr/bin/gsMerge: riga 4: ARG: indice matrice errata **** Impossibile aprire il dispositivo iniziale, uscire. –

+0

@Marius: probabilmente stai usando una vecchia versione di 'bash'. Ho aggiornato la risposta per coprire quel caso. – Idelic

+0

Grazie, Idelico, molto buono. –

7

Per accedere l'ultimo argomento, oltre alla risposta di Idelic sopra, si può anche fare:

echo "${@: $#}" 

Questa legge tutti gli argomenti e li stampa a partire dall'ultimo. In questo modo, è anche possibile accedere agli ultimi N argomenti, ad esempio per gli ultimi tre argomenti:

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

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

Wow, è fantastico. Dove è definito nel manuale? E c'è una versione di gamma di questo? –

+0

Vedere questa risposta: [collegamento] (https://stackoverflow.com/questions/1335815/how-to-slice-an-array-in-bash) sugli array di splicing, la risposta sopra è semplicemente usando quella per tagliare l'array di argomenti di input. –

Problemi correlati