2011-01-03 8 views
18

私はすでにgetoptsについて知っていますが、これは問題ありませんが、必須の引数に対してもフラグを設定する必要があります。引数をとるbashスクリプトを作成するには?

理想的には、私はこの形式で引数を受け取るスクリプトを持ってできるようにしたいと思います:スクリプトは、出力を持っている必要が言う例

script.sh -rvx output_file.txt 

ため

script.sh [optional arguments] [anything required] 

ファイル。これを行う簡単な方法はありますか?

私が知る限り、getoptsを使ってみると、それは次のようになります:script.sh -rvx -f output_file.txtこれはあまりきれいではありません。

私は必要に応じてPythonを使用することもできますが、使用できるのはわずか2.4です。これは少し日付が入ります。

答えて

29

getopts組み込み関数を使用しないで、代わりにgetopt(1)を使用してください。彼らは(微妙に)異なっており、異なることをうまくやっています。

#!/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[@]}" 

はEDIT:完全を期すために、私は引数を必要とするオプションを処理する例を提供してきたあなたシナリオでは、あなたがこれを行うことができます。

+0

これはまさに私が望むように見えます。しかし、これに関する1つの質問:引数をとるフラグ(たとえば、-l file.txt)を許可したい場合、構文は何ですか?再度、感謝します。 –

+0

これについては、getoptのmanページを参照してください。簡単に:オプションにコロンを追加します(例: '" -rv:x "'、引数を取るにはvが必要です)。長いオプションもサポートされています。これは、getopts組み込み関数よりも優先されます。追加の非オプション引数を自分で処理する必要があることに注意してください。 – Sorpigal

+0

ありがとうございました。優れた反応。 –

11

getopsを使用している場合は、case文の後に$OPTIND-1だけシフトしてください。 $*に残っているものは他にもあります。これはおそらくあなたが望むものです。

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

必要な引数が適切な数だけ渡されたことを確認するために$#をチェックして、いつものように$ 1、$ 2などにアクセスしてください。 –

4

あなたは幻想に苦しんでいます。 getoptsを使用する場合は、フラグ文字を前に付ける必須の引数は必要ありません。スクリプトのコーパスから適切な例を見つけようとしました。これは半ば近似です。これはrcsuncoと呼ばれ、RCSからのチェックアウトを取り消すために使用されます。私はしばらくそれを修正していない、私は参照してください。私はそれをかなり頻繁に使用しています(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 

これはほんの半近似です。オプションの引数の後にファイル名を指定しないと、スクリプトは静かに何もしません。しかし、必要な場合は、 'shift'の後に必須引数が存在することを確認することができます。私の別のスクリプトには必須の引数があります。

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

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

ので、そのコマンド(jlss)は、このような-d $HOMEなどのオプションの引数を取ることができますが、installまたはuninstallのいずれかをインストールするには、何かの名前が続く必要があります。それは含まれています。

jlss install program 

しかし、オプションのモードは次のとおりです:使用の基本的なモードがある

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

それは約12のオプションがあるので、私はjlssのすべてを示さなかった - それはrcsuncoほどコンパクトではありませんが。


あなたはオプションの引数の前に必須の引数を扱っていた場合、あなたはもう少し作業を行う必要があるだろう:

  • あなたがからそれらをシフトする、必​​須の引数を拾うと思います方法。
  • 次に、オプションの引数をフラグとともに処理します。
  • 最後に、適切な場合は、追加の 'ファイル名'引数を処理します。

オプション引数(必須のものの前と後ろの両方)に散在する必須の引数を扱っている場合は、さらに多くの作業が必要です。これは多くのVCSシステムで使用されています。 CVSとGITの両方が機能を持っている:

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

、あなたはグローバルオプションを取得するために、1つのgetoptsループを実行します。必須の議論を取り上げる。 2番目のgetoptsループを実行してサブオプションを取得します(そして、 'ファイル名'引数を介して最終ループを実行することもできます)。

人生は楽しいものではありませんか?

2

そして私は、あなたがgetoptを使用してはならないことを、全く逆の事を聞きましたしかしgetoptsは内蔵されています。

Cross-platform getopt for a shell script

のgetoptを使用しないでください(1)。 getoptは空の引数文字列を処理できません。または、空白文字が埋め込まれた 引数です。それまでに が存在したことを忘れてください。

POSIXシェル(およびその他)では、代わりに を使用するのに安全なgetoptsを提供しています。

関連する問題