シェルスクリプトでgetoptsを使うと簡単に引数のオプションが解析が出来ますが、
ポジショナルな引数と一緒に使おうと思うと
解析部分が途中で終わってしまったりうまく行かないことがあります。
ただ使う側としては位置を気にせず使えたほうが便利なことが多いので それを実装する方法について。
getoptsを使ったオプション解析
よくある感じはこんなの。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |  | 
getoptsの後に-始まりで使いたいオプションとして使いたいアルファベットを書きますが、
値を持つものに関しては:を後ろにつけます。
このオプションのアルファベットがOPTに入り、
値持ちの場合はOPTARGにこの値が入ります1
それぞれのオプションに関してcase文でそれぞれに対しての処置を設定します。
もし-付きの引数でgetoptに定義されてないものがくるとOPTには?が入るのでそれに対する処置も追加しておきます。(エスケープ(\?)が必要。)
解析が一通り終わった後、解析に使われなかった残りの引数を取得するために
解析に使われた分(OPTIND - 1)2
だけshiftで削除して残りをポジショナルな引数($1, $2, …)として使えるような形にしています。
実行してみると、
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |  | 
みたいな感じになります。
オプション部分に関しては順番は入れ替わっても大丈夫ですし、
複数回同じオプションを使ってもその度に解析されるので、
上の例だとただ値を入れてるだけなので-c zzz -c ZZZみたいにした場合は後の方が残っています。
ただ、これをオプションより前にポジショナルな引数を与えてしまうと
| 1 2 3 4 5 |  | 
といった感じで解析されません。
また、aは値を持たないオプションですが、-aの後ろに引数を置くとポジショナルな引数としてそこで解析が終わるので、
| 1 2 3 4 5 |  | 
といった感じに-aの解析だけ行われて終了してしまいます。
ポジショナルな引数をオプションの前や間にも入れられるようにする
これに関してはstackoverflowに10年以上前の質問がありました。
一番voteされてるのは普通のgetoptsの説明で答えになってない感じではあるんですが、
8年経って投稿された答えがいい感じに解決してくれてます。
上のスクリプトを下のように書き換えてみます。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |  | 
これを実行すると
| 1 2 3 4 5 |  | 
といった感じでオプション解析に使われてないものが
positionalに入れられてそれを順に使えるような状態が出来ます。
ここでは
| 1 2 |  | 
の組み合わせにすることでgetoptsで1つずつ解析していき、
かつ-始まりでないポジショナルな引数が来たらこの2段目がfalseになるので、
そこでは
| 1 2 |  | 
としてpositional変数にその値を追加しています
3。
この場合はgetoptsでのOPTINDのインクリメントが行われないので
手動で1つ値を加えておきます。
こうすることで最後までオプション引数があれば解析してその他はポジショナルな引数として扱うことが出来ます。
オプションでない-で始まる引数をポジショナルなものとして扱う
上のスクリプトでオプションとして設定していない文字を-付きで与えると、
| 1 2 3 |  | 
といった感じのエラーを出します。
このような設定していないものはそのままポジショナルな引数として使いたい、といったことがある場合は以下のようにすることで扱えます。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |  | 
変わったところはgetoptsの引数の最初に:が追加され、?の場合に
positionalに-を加えたOPTARGを追加している部分。
getoptsの第一引数の文字列で一番最初に:を入れると
-から始まる引数が指定のオプションでない場合はエラーにせずに
その文字をOPTARGに入れる、という仕組みがあります。
この場合もOPTに入るのは?です。
これを使って-$OPTARGをpositionalに加えることでオプション指定していない-引数をポジショナルな引数として扱っています。
| 1 2 3 4 5 |  | 
こんな感じ。
引数の一部を解析した上で さらに別の関数にそのまま渡したい、とか言う場合に使えそうです。
