2011-01-03 24 views
18

Już wiem o getopts, i to jest w porządku, ale denerwuje to, że musisz mieć flagę nawet dla obowiązkowych argumentów.Jak utworzyć skrypt bash, który pobiera argumenty?

Idealnie, chciałbym móc mieć skrypt, który odbiera argumenty w tej formie:

script.sh [optional arguments] [anything required] 

np

script.sh -rvx output_file.txt 

gdzie skrypt mówi, że musisz mieć wyjście plik. Czy jest jakiś łatwy sposób to zrobić?

O ile wiem, z getopts musiałby wyglądać tak: script.sh -rvx -f output_file.txt, a to po prostu niezbyt czyste.

Mogę również użyć pythona w razie potrzeby, ale mam tylko 2,4 dostępne, co jest nieco przestarzałe.

Odpowiedz

29

Nie używaj wbudowanego getopts, zamiast tego użyj getopt (1). Są (subtelnie) różne i robią różne rzeczy dobrze. Dla twojego scenariusza możesz to zrobić:

#!/bin/bash 

eval set -- $(getopt -n $0 -o "-rvxl:" -- "[email protected]") 

declare r v x l 
declare -a files 
while [ $# -gt 0 ] ; do 
     case "$1" in 
       -r) r=1 ; shift ;; 
       -v) v=1 ; shift ;; 
       -x) x=1 ; shift ;; 
       -l) shift ; l="$1" ; shift ;; 
       --) shift ;; 
       -*) echo "bad option '$1'" ; exit 1 ;; 
       *) files=("${files[@]}" "$1") ; shift ;; 
     esac 
done 

if [ ${#files} -eq 0 ] ; then 
     echo output file required 
     exit 1 
fi 

[ ! -z "$r" ] && echo "r on" 
[ ! -z "$v" ] && echo "v on" 
[ ! -z "$x" ] && echo "x on" 

[ ! -z "$l" ] && echo "l == $l" 

echo "output file(s): ${files[@]}" 

EDYCJA: dla kompletności podałem przykład obsługi opcji wymagającej argumentu.

+0

Wygląda na to, że robi dokładnie to, co chcę. Jedno pytanie z tym jednak: jeśli chcę zezwolić na flagę, która przyjmuje argument (na przykład -l plik.txt), jaka byłaby składnia? Dzięki jeszcze raz. –

+0

Zajrzyj na stronę man getopt. Pokrótce: dodaj dwukropek do opcji (np. '-rv: x" ', co wymaga v, aby przyjąć argument). Obsługiwane są również długie opcje, co jest jednym ze sposobów na przejęcie wbudowanego getoptu. Zauważ, że sam będziesz musiał obsługiwać dodatkowy argument nie będący opcją. – Sorpigal

+0

Dziękuję bardzo. Doskonała odpowiedź. –

11

Jeśli używasz getops, po prostu przesuń o $OPTIND-1 po swoim przypadku. To, co pozostanie w $*, będzie wszystkim, czego prawdopodobnie potrzebujesz.

shift $((${OPTIND} - 1)); echo "${*}" 
+0

Yup. Po prostu sprawdź $ #, aby upewnić się, że została podana właściwa liczba wymaganych argumentów, a następnie jak zwykle uzyskaj dostęp do nich w postaci 1 $, 2 $ itd. –

4

Cierpicie z powodu iluzji; użycie getopts nie wymaga obowiązkowych argumentów przedrostka oznaczonego flagą. Próbowałem znaleźć odpowiedni przykład z mojego korpusu skryptów; jest to przyzwoite przybliżenie. Nazywa się rcsunco i służy do anulowania zamówienia z RCS. Nie zmieniłem tego od jakiegoś czasu, widzę; Używam go dość często (ponieważ nie przeszedłem jeszcze pełnej migracji z RCS).

#!/bin/sh 
# 
# "@(#)$Id: rcsunco.sh,v 2.1 2002/08/03 07:41:00 jleffler Exp $" 
# 
# Cancel RCS checkout 

# -V print version number 
# -n do not remove or rename checked out file (like SCCS unget) (default) 
# -r remove checked out file (default) 
# -k keep checked out file as $file.keep 
# -g checkout (unlocked) file after clean-up 
# -q quiet checkout 

: ${RCS:=rcs} 
: ${CO:=co} 

remove=yes 
keep=no 
get=no 
quiet= 

while getopts gknqrV opt 
do 
    case $opt in 
    V) echo "`basename $0 .sh`: RCSUNCO Version $Revision: 2.1 $ ($Date: 2002/08/03 07:41:00 $)" | 
     rcsmunger 
     exit 0;; 
    g) get=yes;; 
    k) keep=yes;; 
    n) remove=no;; 
    q) quiet=-q;; 
    r) remove=yes;; 
    *) echo "Usage: `basename $0 .sh` [-{n|g}][-{r|k}] file [...]" 1>&2 
     exit 1;; 
    esac 
done 

shift $(($OPTIND-1)) 

for file in $* 
do 
    rfile=$(rfile $file) 
    xfile=$(xfile $rfile) 
    if $RCS -u $rfile 
    then 
     if [ $keep = yes ] 
     then 
      if [ -f $xfile ] 
      then 
       mv $xfile $xfile.keep 
       echo "$xfile saved in $xfile.keep" 
      fi 
     elif [ $remove = yes ] 
     then rm -f $xfile 
     fi 
     if [ $get = yes ] && [ $remove = yes -o $keep = yes ] 
     then $CO $quiet $rfile 
     fi 
    fi 
done 

To tylko przyzwoite przybliżenie; skrypt cicho nic nie robi, jeśli nie podaje się nazw plików po opcjonalnych argumentach. Jeśli jednak zajdzie taka potrzeba, możesz sprawdzić, czy obowiązkowe argumenty są obecne po "przesunięciu". Inny mój skrypt ma obowiązkowe argumenty. Zawiera on:

... 
shift $(($OPTIND - 1)) 

case $# in 
2) case $1 in 
    install) MODE=Installation;; 
    uninstall) MODE=Uninstallation;; 
    *)   usage;; 
    esac;; 
*) usage;; 
esac 

Tak, że komenda (jlss) może podjąć argumentów opcjonalnych, takich jak -d $HOME, ale wymaga też install lub uninstall następuje nazwa czegoś do zainstalowania. Podstawowy tryb użytkowania jest:

jlss install program 

Ale jest opcjonalny tryb:

jlss -d $HOME -u me -g mine -x -p install program 

nie pokazują wszystkich jlss ponieważ ma około 12 opcji - to nie jest tak zwarty jak rcsunco .


Jeśli do czynienia z obowiązkowych argumentów przed argumentami opcji, a następnie trzeba by zrobić trochę więcej pracy:

  • Można by podnieść obowiązkowe argumenty, przenosząc je z droga.
  • Następnie przetwarzane są opcjonalne argumenty z flagami.
  • Wreszcie, jeśli jest to właściwe, obsługujesz dodatkowe argumenty "nazwa pliku".

Jeśli masz do czynienia z obowiązkowymi argumentami przeplatanymi argumentami opcji (zarówno przed, jak i po obowiązkowych), masz jeszcze więcej pracy do wykonania. Jest używany przez wiele systemów VCS; CVS i GIT oba mają obiekcie:

git -global option command [-sub option] [...] 

Tutaj uruchomić jeden getopts pętlę, aby uzyskać opcje globalne; podnieś obowiązkowe argumenty; i uruchom drugą pętlę getopts, aby uzyskać podopcje (i może uruchomić końcową pętlę nad argumentami "nazwa pliku").

Czy zabawa nie jest przyjemnością?

2

I usłyszałem zupełnie coś przeciwnego, że nie należy używać getopt, ale wbudowany getopts.

Cross-platform getopt for a shell script

wolno używać getopt (1). getopt nie może obsługiwać pustych ciągów argumentów lub argumentów z osadzonymi białymi znakami. Zapomnij, że kiedykolwiek istniał .

Powłoka POSIX (i inne) oferują getopty, które można bezpiecznie używać zamiast tego.

Powiązane problemy