Shell-Tips

【Shell-Tips】getoptsとusageを実装してみる。

シェルには、コマンドのオプシヨンを解析したリチェックしたりするための、getoptsというコマンドが用意されています。

レビュー時にいつも思うのは、この「getOpts」を使用するエンジニアが少ないこと・・

「getOpts」コマンドは、シェルに対して「-」と"アルファベット1文字"でオプションを指定された場合、それを解析するコマンドです。オプションによって挙動を変えたい時にcase文と共に用います。

実際には習うより慣れろが正しいため、下記にサンプルを実装します。

「getOpts」コマンド

「getOptsコマンドを使うと何がうれしいの?」とよく聞かれることがあります。特にうれしいことはありませんが(笑う・・楽です

もし、シェルスクリプトの引数処理で何かの制御をおなう場合、一番初めに考えれらるのが「if」文だと思いますが、「if」文で引数を制御する場合はパラメータの順番に気を遣わなければならなくなります。

仮にバックアップ用のシェルスクリプト「backup.sh」を作成した場合、必要となる要素は「バックアップ対象」と「バックアップ格納先」になると思います。

ハードコーディング(ソースべた書き)でも良いのですが、それだと「backup.sh」が汎用的に使用できないモノになってしまうため、通常はまず引数で情報の受け渡しを考えるはずです。

if文の場合

# バックアップシェル実行形式
$ backup.sh <バックアップ対象> <バックアップ先パス

# 「backup.sh」内部の引数チェックロジック
#!/bin/sh
checkArgs() {
  if [ -f ${1} ]; then
    src=<バックアップ対象
  fi
  if [ -d ${2} ]: then
    dst=<バックアップ先パス
  fi
}

上記がその際に考えられる実行形式になると思います。

この場合、もし第一引数の<バックアップ対象>に値がはいっていなかった場合どうなるでしょう。値が空であるため、第二引数の<バックアップ先>が第一引数として実行されてしまうのです。

# バックアップシェル実行形式
$ backup.sh <バックアップ対象(空)> <バックアップ先パス

# 「backup.sh」内部の引数チェックロジック
#!/bin/sh
checkArgs() {
  if [ -f ${1} ]; then
    src=<バックアップ先パス
  fi
  if [ -d ${2} ]: then
    dst=
  fi
}

チェックが甘くて正常終了してしまった場合、あるはずのバックアップが存在しないことになってしまいます。

getOptsの場合

判り易くバックアップ対象を「-s(source)」、バックアップ先パスを「-d(destination)」としておきます。

# バックアップシェル実行形式
$ backup.sh -s <バックアップ対象> -d <バックアップ先パス

#!/bin/sh
#-s /-d オプションを指定した場合に出すメッセージを変更する
while getopts s:d: opts
do
  case $opts in
    s ) src=$OPTARG ;;
    d) dst=$OPTARG ;;
    * ) usage
       exitLog ${JOB_WR} ;;
  esac
done;

while」文の隣に「getOpts」コマンドを記述します。getoptsの次に書かなくてはならない引数は、このシェルスクリプトで処理させようとするオプションを並べたものになります。

もしそのオプションが値を必要とするものならば、その直後に「:(コロン)」を付けます。つまり「while getopts s:d: opts」となります。

:(コロン)」を付けたオプションの値は、$OPTARGと言いう変数に自動的に格納されます。よって「while」文直下の「case」文の処理では、$OPTARGに代入された値をスクリプト内の変数へ代入します。「src=$OPTARG

上記のロジックの場合、「-s(source)」、バックアップ先パスを「-d(destination)」何方でもないオプション(例えば[ r ]など)が引数と渡された場合、「case」文の「*)」でキャッチされます。

上記の例では「usage」がコールされ、処理が「exitLog」へ引き渡されます。

「Usege」関数

この「Usage」関数は、特にシェルに用意されているモノでありません。「ヒアドキュメント」を使用して、作成したシェルの実行方法や引数などを表示する自作関数です。

記述方法は簡単で、「ヒアドキュメント」を関数かしただけです。

実際に作成してみます。

usage() {
cat <<EOUSAGE
-----------------------------------------------------------------
Usage: $0 [< options >]
Options:
-s backup_target : Specifies the target file or target to backcup.
-d destination_path : Specify the backup storage directory path.
------------------------------------------------------------------
EOUSAGE
}

これだけです。「$0」は実行しているスクリプト名を表示します。つまり自分の名前です。

EOUSAGEは「End Of Usage」の略です。特に制約等はありませんので開始と終了が同じ文字列なら「EOF」でもなんでもかまいません。

このように「ヒアドキュメント」以外に、特にロジックというロジックはありません。(笑

上記「usage」は、「case」文の「*)」でキャッチされ、実行されます。つまり間違えた引数を指定してシェルを実行した場合、エラーと一緒に出力される自作ヘルプメッセージです。

「usage」の実行結果

[root@CentOS7 bin]# sh func.sh -s /src -r /dst
[root@CentOS7 bin]# cd ../log
[root@CentOS7 log]# cat func.log
2020-05-12 16:42:13 [ pre ] SCRIPT:[ func.sh ] PID:[ 11858 ] STARTED LOG.
func.sh: 不正なオプションです -- r
-----------------------------------------------------------------
Usage: func.sh [< options >]
Options:
-s backup_target : Specifies the target file or target to backcup.
-d destination_path : Specify the backup storage directory path.
------------------------------------------------------------------
2020-05-12 16:42:13 [ pre ] SCRIPT:[ func.sh ] PID:[ 11858 ] ENDED LOG with ERROR.

どうでしょう? それなりに見えませんか?

「オレ(ワタシ)って意外といけるんじゃね?」と思っていただけると嬉しいです。

最後に、上記を実行したシェルスクリプトを載せておきます。

実行シェルスクリプトを作成する

getOptsを使用したシェルスクリプトを作成します。

このサンプルでは、getopts の基本動作を理解しやすくするために、最低限の引数チェックのみを行っています。実務スクリプトでは、必須オプションの有無や入力値の妥当性をさらに厳密に検証する処理を追加してください。

なお、ログの出力には下記の共通ログ出力クラスおよび共通関数定義クラスを使用しています。

前提となる実行環境

Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。

実行環境

BASE_DIR(任意のディレクトリ)

  • scripts
    • bin(実行スクリプト格納領域)
      • <<各種実行スクリプト>>.sh (実行ファイル)
    • com(共通スクリプト格納領域)
      • logger.shrc(共通ログ出力ファイル)
      • utils.shrc(共通関数定義ファイル)
    • etc(設定ファイル等の格納領域)
      • infraMessage.conf(メッセージ定義ファイル)
    • log(スクリプト実行ログの格納領域)
      • スクリプト名.log 
    • tmp(テンポラリ領域)
    • rep(レポート出力領域)

引数なしで実行

引数なしで実行すると、checkArgs()関数で引数がないためusageが出力されます。

sh func.sh

【出力例:】

2025-10-17 08:43:22 [ INFO ] [ pre ] SCRIPT:[func.sh] PID:[293526] STARTED LOG.
2025-10-17 08:43:22 [ ERROR ] [ pre ] no arguments specified.
-----------------------------------------------------------------
Usage: func.sh [< options >]
Options:
-b backup_target : Specifies the target file or target to backcup.
-m destination_path : Specify the backup storage directory path.
------------------------------------------------------------------
2025-10-17 08:43:22 [ WARNING ] [ pre ] SCRIPT:[func.sh] PID:[293526] ENDED LOG.

引数ありで実行

引数をつけて実行すると、getOptsによって適切な変数へ引数が格納され、ログに出力されます。

sh func.sh -s /src -d /dst

【出力例:】

2025-10-17 08:50:18 [ INFO ] [ pre ] SCRIPT:[func.sh] PID:[298173] STARTED LOG.
src=/src dst=/dst
2025-10-17 08:50:18 [ INFO ] [ post ] SCRIPT:[func.sh] PID:[298173] ENDED LOG.

実践環境を整える

ここまで学んだ知識を実際に試すには、Linuxを動かす環境が必要です。手軽に始めるならVPSを利用するのがおすすめです。
VPS徹底比較!ConoHa・さくら・Xserverの選び方



VPSを利用してLinux環境を準備したら、実際の設定は下記の記事が参考になります。
VPSに開発環境を自動構築する方法|Apache+Tomcat+PostgreSQL

よく読まれている記事

1

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか? 無料で使えるだけでなく、高い柔軟 ...

2

Linux環境でよく目にする「Vim」という名前。サーバーにログインしたら突然Vimが開いてしまい、「どうやって入力するの?」「保存や終了ができない!」と困った経験をした人も多いのではないでしょうか。 ...

3

ネットワーク技術は現代のITインフラにおいて不可欠な要素となっています。しかし、ネットワークを深く理解するためには、その基本となる「プロトコル」と「レイヤ」の概念をしっかり把握することが重要です。 こ ...

4

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

5

Javaは世界中で広く使われているプログラミング言語であり、特に業務システムやWebアプリケーションの開発において欠かせない存在です。本記事では、初心者向けにJavaの基礎知識を網羅し、環境構築から基 ...

-Shell-Tips