LoginSignup
42
40

More than 3 years have passed since last update.

シェルスクリプト オプション解析 徹底解説 (getopt / getopts)

Last updated at Posted at 2019-10-21

はじめに

シェルスクリプトでオプション・引数解析といったらまず挙がるのが getoptgetopts です。さてどちらを使うべきでしょうか?始めに断っておくと実は私はどちらも積極的には使っていません。なぜなら独自実装でもほとんどコードは変わらず、より柔軟な処理ができるからです。とはいえ getoptgetopts はシェルスクリプトの基本なのでこれらの使い方について解説したいと思います。(解説が不要な人はそれぞれの「使用方法」を読んでください。)

本編の前に

この記事を書いたあと独自実装のオプション解析コードを書き最終的に getoptgetopts よりも高機能で使いやすいオプションパーサー getoptions を開発しました。もはやちまちまとしたコードを手書きする作業は不要です。シェルスクリプトで簡単に引数解析したいだけという方にはこちらをおすすめします。POSIXシェル準拠で getoptions コマンドをインストールするだけで環境依存せずに使えますし、オプションパーサーを事前生成すれば getoptions なしで動かすこともできます。詳細は以下のリンクから(時系列に関連記事を並べてます。基本的に最後の記事を見ればよいです。)

getoptgetopts の違い

getoptgetopts の違いですが、まず getopt は外部コマンドで POSIX では規定されていません(関数としては規定されています (getopt)。それに対して getopts はシェルビルトインコマンドで POSIX で規定されています (getopts)。そのためすべてのPOSIX準拠シェルで実装されている getopts の方が移植性が高くなります。

また getopt は大きく2種類存在しており、オリジナル版(BSD, macOS 版も同等)は最も機能が少なく GNU 版は高機能です。(このドキュメントでは macOS 版と GNU 版で検証しています。)

英語版 Wikipedia の getopts にはこのように書かれています。

getopts was first introduced in 1986 in the Bourne shell shipped with Unix SVR3.

getopts was developed as an improvement to the original getopt Unix program.
The original getopt program had fewer features than getopts.

An alternative to getopts is the GNU enhanced version of getopt.

つまり歴史的にみると以下のようになると思われます。(想像です)

  1. より少ない機能を持った getopt (オリジナル版) が作られた。
  2. getopt の機能を強化した getopts が作られた。
  3. GNU 版では getopt を拡張することで getopts よりも高機能になった。
    (一方で macOS を 含む BSD 版は、オリジナル版と同等なので機能が少ない。)

それぞれの機能の違いの概略を以下に示します。

getopt getopts getopt (GNU版) 補足
ショートオプション Yes Yes (POSIX) Yes -x
結合されたショートオプション Yes Yes (POSIX) Yes -xy
オプション引数 Yes Yes (POSIX) Yes -x value, -xvalue
省略可能なオプション引数 - - Yes -x or -x value
引数に空白を含めることができる - Yes (POSIX) Yes "next day" のような引数
エラーメッセージの抑制 Yes Yes (POSIX) Yes
エラーメッセージのカスタマイズ - Yes (POSIX) -
ロングオプション - - Yes
オプションとオプション以外の混在 - - Yes
- で始まるロングオプション - - Yes -exec
+ で始まるオプション - zsh, ksh, mksh - +x

GNU 版 getopt が最も高機能ですが、BSD や macOS を考慮する場合は、getopts を使うしかありません。ただしロングオプションは使えません。

  • homebrew でよければ GNU版 getopt である gnu-getopt がインストール可能です。
  • 頑張れば getopts を使いつつロングオプションに対応することも出来るようですが、かなり無理した実装ばかりなので、それをやるぐらいなら独自実装の方が簡単です。

さてこれよりそれぞれのコマンドの詳細な使い方について解説したいと思いますが、歴史的な流れに従って「getopt(オリジナル版)」「getopts」「getopt(GNU版)」の順で解説します。

getopt (オリジナル版)

まず GNU 拡張を含まない(おそらく)オリジナル版の getopt の解説です。macOS を含む BSD 版の動作も同じです。オリジナル版の getopt は引数に空白文字を含めることが出来ないという大きな欠点があるので推奨しません。移植性があり引数に空白文字を含めることができる getopts の方が優れているので、オリジナル版を使う理由はないのですが getopts と GNU 版 getopt の前提知識として必要なため解説します。

getopt は一般的にオプション解析をするためのコマンドと言われていますが、オプション解析をしやすくするために引数を整形するためのコマンドと捉えたほうが正確です。例えば -ab のようなオプションを -a -b に分離したり、-xvalue のようなオプションを -x value に分離したりします。

getopt の使用方法は以下のとおりです。

getopt optstring parameters

第一引数の optstring にオプションとして解析したい文字(このドキュメントでは「オプション文字列」と呼ぶことにします。)を指定します。parametersgetopt で整形させる引数です。

getopt による出力(整形)の例を以下に示します。

呼び出し 出力
getopt abc -a -b -c -a -b -c --
getopt abc -abc -a -b -c --
getopt abc -a -b -c foo bar baz -a -b -c -- foo bar baz
getopt a:bc -afoo -bc -a foo -b -c --
getopt abc -a foo -b bar -c -a -- foo -b bar -c
getopt a:bc -a foo -b bar -c -a foo -b -- bar -c

※ GNU 版では環境変数 POSIXLY_CORRECT を定義すると同等の出力になります。

getopt の機能

ショートオプション

オプション文字列に a と指定すると オプション -a が使えるようになります。オプションとオプション以外は -- を挟んで前後に分割されます。

呼び出し 出力
getopt a -a -a --
getopt a --
getopt a foo -- foo
getopt a -a foo -a -- foo

結合されたショートオプション

(オプション引数を取らない)オプションは -abc のようにまとめて書くことが出来ます。まとめて書いても getopt が分解してくれるのでオプション解析が楽になります。

呼び出し 出力
getopt abc -abc -a -b -c --

オプション引数

オプション文字列の各文字の後に : をつけると「オプション引数」を持つオプションという意味になります。オプション引数はオプションにつなげて指定する方法と、スペースで区切って次の引数で指定する方法があります。

呼び出し 出力 補足
getopt a: -a bc -a bc --
getopt a: -abc -a bc --
getopt a: -a -x -a -x -- この場合の -x-a のオプション引数であってオプションではありません

エラーメッセージ

不明なオプション、もしくはオプション引数がない場合は、エラーメッセージを出力し終了ステータスが非0で終了します。

呼び出し エラー出力(例)
getopt a: -x getopt: 無効なオプション -- 'x'
getopt a: -a getopt: オプションには引数が必要です -- 'a'

オプション文字列の先頭に : をつけるとエラーメッセージの出力を抑制することが出来ます。抑制するのはエラーメッセージの出力だけで、エラーが発生した時の終了ステータスは非0です。終了ステータスでエラーになったことはわかりますが、エラーとなったオプションや理由はわかりません。そのため getopt を使用する場合はデフォルトのエラーメッセージを使用したほうが良いでしょう。

使用方法

位置パラメータへの設定

まずオプションを解析を行うために getopt で整形した引数(出力)を位置パラメータ($1, $2 ...)に設定します。

args=$(getopt abc $*) || exit 1
# args=`getopt abc $*` 同等の意味の古い書き方

set -- $args
# eval "set -- $args" # zsh の shwordsplit に対応するにはこちらを使う

時折、以下のように変数に入れずにいきなり set している例を見かけますが、これだと getopt でエラーが発生しても set 呼び出しで正常終了になってしまうため間違った使い方です。(同様に for ... in に直接渡すのもよくありません。)

set -- $(getopt abc $*)

ところで macOS (BSD) の man getopt には以下のような記述があります。

you should not use `getopt abo: "$@"` since that would parse
the arguments differently from what the set command below does.

どうやら、getopt abc "$@" としてはいけないようです。おそらく IFS の値によって、set コマンドと異なる解釈になるのを避けるためだと思うのですが納得できていません。getopt コマンドは引数をスペース区切りでしか出力しないので、結局の所 IFS はスペース区切り前提にするしか無いと思います。釈然としませんがオリジナル版の getopt を使うことはないのでこれ以上追求しないことにします。理由をご存じの方はコメントで教えて下さい。

オプション解析

位置パラメータへ設定したら次はループを使ってオプションを解析していきます。ループには forwhile がありますが、どちらを使っても殆ど変わりません。

まずは for を使った例です。

# 位置パラメータへの設定
args=$(getopt a:b $*) || exit 1
set -- $args

# オプション解析のためのループ
for opt in "$@"; do # in "$@" を省略して for opt と書くことも出来ます。
  case $opt in
    -a) A_VALUE=$2; shift 2 ;;
    -b) B_FLAG=1; shift ;;
    --) shift; break ;;
  esac
done

次に while を使った例です。

# 位置パラメータへの設定 は 同じなので省略

# オプション解析のためのループ
while [ $# -gt 0 ]; do
  case $1 in
    -a) A_VALUE=$2; shift 2 ;;
    -b) B_FLAG=1; shift ;;
    --) shift; break ;;
  esac
done

ループ変数 opt を使用するか位置パラメータ $1 を使用するかの違いだけです。while の場合に shift が必要なのは当然として、なぜ for でも shift が必要なのでしょうか? それはオプション引数を参照するためです。for を使って現在のオプションが opt 変数に代入されたとしても、オプションの次にあるオプション引数はわかりません。処理済みのオプションを shift していくことで、オプション引数は常に位置パラメータ $2 から取得できるようになります。オプションは opt 変数、オプション引数は位置パラメータ $2 と違う方法で取得することになるので個人的には while の方が好みです。もしオプション引数が必要ないなら shift も必要なくなるので for の方がわずかにシンプルになります。

getopts

getopt が引数を整形するコマンドに対して、getopts は呼び出すたびに一つずつオプションを読み取る関数です。オリジナル版の getopt とは違い引数に空白文字が含まれていても問題ありません。解析したオプションは指定したシェル変数に代入され、オプション引数が存在する場合は OPTARG 変数に代入されます。全てのオプションの解析が終わると、getopts は 終了ステータスとして非0を返し、OPTIND 変数にはオプション以外の残りの引数(オペランド)を処理できるよう、最初のオペランドのインデックス番号が代入されます。シェルビルトインコマンドとして実装されたことによりシェル変数を使うようになったのが大きな特徴で getopt に比べてシンプルな使い方になっています。

getopts による出力例を以下に示します。

呼び出し OPT (実際は指定した名前) OPTARG OPTIND
getopts abc OPT -a -b -c 1回目 a, 2回目 b, 3回目 c 4
getopts abc OPT -abc 1回目 a, 2回目 b, 3回目 c 2
getopts abc OPT -a -b -c foo bar baz 1回目 a, 2回目 b, 3回目 c 4
getopts a:bc OPT -afoo -bc 1回目 a, 2回目 b, 3回目 c 1回目 foo 3
getopts abc OPT -a foo -b bar -c 1回目 a 2
getopts a:bc OPT -a foo -b bar -c 1回目 a, 2回目 b 1回目 foo 4

※ 全てのオプション解析が終わった時(= getopts が非0を返した時)に OPT 変数に代入される値は POSIX 仕様では未定義のようです。殆どのシェルでは ? になりますが zsh では最後に読み取ったオプションでした。

getopts の機能

getopts の使用法方は以下のとおりです。

getopts optstring name [args]

オプション文字列の意味は、オリジナル版の getopt と同じなので省略します。第二引数は変数名で読み取ったオプションが代入されます。argsgetopts に解析させたい引数で省略された場合は現在の位置パラメータ "$@" を指定したのと同じ意味になります。

getopts の仕様 によるとオプション文字列に使用できる文字は英数字のみで、その他の文字を使用した場合の結果は不定です。(The use of other option characters that are not alphanumeric produces unspecified results.) getopts でロングオプションに対応させる方法としてオプション文字列に - を含めるやり方がありますが、POSIX 的には好ましくありません。

エラーメッセージ

getopts では独自のエラーメッセージに変更することが可能です。エラーメッセージ抑制する方法は getopt と同じくオプション文字列の先頭を : にします。エラーが発生すると、エラーメッセージは抑制され (getopt の場合とは違い)終了ステータスは 0 となります。発生したエラーが「不正なオプション」の場合は第二引数で指定した変数に ? が代入され、OPTARG 変数に不正なオプション文字が代入されます。発生したエラーが「オプション引数がない」場合は第二引数で指定した変数に : が代入されます。

呼び出し OPT OPTARG
getopts :a OPT -x ? x
getopts :a: OPT -a :

※ bash では OPTERR 変数に 0 を設定してもエラーメッセージを抑制することができます。OPTERR 変数は POSIX の初期の提案でなされたものですが : を指定する方法に置き換わり bash 以外は対応していません。

+ で始まるオプション

zsh, mksh, ksh では + で始まるオプションを受け付けることが出来ますが、これは POSIX の仕様ではありません。

zsh と mksh では + で始まるオプションを受け付けるために特にすることはありません。そのため、+ で始まる(オプションではない)引数が意図せずオプションとして扱われてしまう可能性があるので注意してください。ksh ではオプション文字列の先頭(エラーメッセージを抑制する : がある場合はその次)を + にします。

呼び出し OPT (zsh, mksh) OPT (ksh)
getopts ab OPT +b +b ?
getopts +ab OPT +b +b +b
getopts +ab OPT ++ ++ ?

OPTIND 詳細

getopts は実行するたびにオプションを一つずつ処理していきます。つまりどこまで処理したかという状態を持っているわけです。その状態を持っている変数が OPTIND 変数です。OPTIND 変数に 1 を代入するとこの状態はリセットされ、新たなオプションを解析することができます。

さて以下のようなコードで、実行するたびに OPTIND 変数がどのように変わるか確認してみましょう。

echo "OPTIND:$OPTIND (start)"

set -- -a -bc -d data -e

while getopts abcd:e OPT; do
  echo "OPT:$OPT OPTIND:$OPTIND"
done

echo "OPT:$OPT OPTIND:$OPTIND (end)"
行番号 出力 (dash, mksh) 出力 (bash, ksh, posh) 出力 (zsh) 出力 (yash)
1 OPTIND:1 (start) OPTIND:1 (start) OPTIND:1 (start) OPTIND:1 (start)
2 OPT:a OPTIND:2 OPT:a OPTIND:2 OPT:a OPTIND:1 OPT:a OPTIND:1:2
3 OPT:b OPTIND:3 OPT:b OPTIND:2 OPT:b OPTIND:2 OPT:b OPTIND:2:2
4 OPT:c OPTIND:3 OPT:c OPTIND:3 OPT:c OPTIND:2 OPT:c OPTIND:2:3
5 OPT:d OPTIND:5 OPT:d OPTIND:5 OPT:d OPTIND:5 OPT:d OPTIND:5
6 OPT:e OPTIND:6 OPT:e OPTIND:6 OPT:e OPTIND:5 OPT:e OPTIND:5:2
7 OPT:? OPTIND:6 (end) OPT:? OPTIND:6 (end) OPT:e OPTIND:6 (end) OPT:? OPTIND:6 (end)

なんとバラバラです。特に yash の出力はどういうことでしょうか?

OPTIND 変数の内容を次に処理すべきインデックス番号と仮定すると、-a -bc -d data -e という引数の場合に、1番目の引数 -a を処理するときは 1 ですが、さて2番目の引数のうち -c を処理するときはどうなるべきでしょうか?

つまりショートオプションが結合されてる場合ではインデックス番号の数値一つだけでは足りないのです。そのため yash では : 区切りで二つの数値を OPTIND 変数に持っているわけです。他のシェルでは内部に見えない状態変数を持っているようです。

getopts によると、OPTIND 変数は、getopts が非0で終了した時に、オプションを除くの最初の引数のインデックス番号になるとしか規定されてないようです。つまり途中の値がそれぞれ違っていても POSIX 仕様上は何の問題もなさそうです。(話がそれますが、zshの7行目の出力 OPT の値は e ですが POSIX ではオプション解析処理が終了したときに ? にするとなってるので POSIX 準拠してないようです。)

さて、上の方で「OPTIND 変数に 1 を代入するとリセットされる。」と書きました。その検証をしてみます。

set -- -o -x # パターン1
# set -- -ox # パターン2
getopts ox OPT1
OPTIND=1
getopts ox OPT2
echo "$OPT1 $OPT2" # すべて o o と表示されるはず
パターン 出力 (dash, bash, ksh, mksh, yash) 出力 (zsh) 出力 (posh)
パターン1 o o o x o o
パターン2 o o o x o x

zsh と posh ではリセットされませんでした。POSIX に準拠していないということでしょうか? zsh や posh では OPTIND 変数を unset することで状態をリセットできましたが、unset すると、dash でエラーになりました。0 を代入すると yash でおかしくなります。どのシェルでも動く汎用的なリセット方法は見つからなかったのでシェル毎にリセット方法を変えるしかなさそうです。

使用方法

もっともシンプルな例はこんな感じでしょうか?

while getopts a:b OPT; do
  case $OPT in
    a) A_VALUE=$OPTARG ;;
    b) B_FLAG=1 ;;
    *) exit 1 ;; # 不正なオプション または オプション引数がない場合(OPT = ?)
  esac
done
shift $((OPTIND - 1))

getopt と比べて簡単になっている点は、事前の引数の整形が必要ないので位置パラメータへの設定が不要であるのと、オプション引数を飛ばす処理を getopts が行うのでオプション毎の shift が不要になっている点です。代わりにオプション解析でエラーが発生したときの中断処理と残りの引数を処理するための shift $((OPTIND - 1)) が増えています。

上記のコードは、オプション解析でエラーが発生した時のメッセージを getopts にまかせていますが、メッセージをカスタマイズしたい場合は以下のようになります。エラーメッセージを抑制すると OPT 変数に入っている文字でエラーの内容を区別することができます。

while getopts :a:b OPT; do
  case $OPT in
    a) A_VALUE=$OPTARG ;;
    b) B_FLAG=1 ;;
    :) echo "Mission arg: -$OPTARG" >&2; exit 1 ;; # オプション引数がない (OPT = :)
    *) echo "Unknown option: -$OPTARG" >&2; exit 1 ;; # 不正なオプション (OPT = ?)
  esac
done
shift $((OPTIND - 1))

getopt (GNU版)

GNU 版の getopts の使用法方は以下のとおりです。

  1. getopt optstring parameters
  2. getopt [options] [--] optstring parameters
  3. getopt [options] -o|--options optstring [options] [--] parameters

1 はオリジナル版の getopt に近い動きとなり、引数に空白や特殊文字が使えません。 2, 3 が GNU で拡張された動きになります。個人的には 2 は直感的でないと感じるので、3 をおすすめします。

GNU 版の getopt による出力例を以下に示します。

呼び出し 出力
getopt -o abc -- -a -b -c -a -b -c --
getopt -o abc -- -abc -a -b -c --
getopt -o abc -- -a -b -c foo bar baz -a -b -c -- 'foo' 'bar' 'baz'
getopt -o a:bc -- -afoo -bc -a 'foo' -b -c --
getopt -o abc -- -a foo -b bar -c -a -b -c -- 'foo' 'bar'
getopt -o a:bc -- -a foo -b bar -c -a 'foo' -b -c -- 'bar'

GNU版 getopt の機能

ロングオプション

-l または --longoptions でロングオプションを指定できます。ロングオプションはカンマ区切りで複数指定できます。ロングオプションだけを指定する場合でも、ショートオプションを指定する -o または --options は省略できないことに注意してください。

呼び出し 出力 補足
getopt -o '' -l long-a,long-b -- --long-a --long-b --long-a --long-b --
getopt -o '' -l reverse,recursive -- --rev --reverse -- オプション名は短縮指定できます

ロングオプションのオプション引数

ショートオプションと同様に、オプション名の最後に : をつけることで指定します。オプション引数はスペースで区切る他、オプションに = でつないで渡します。

呼び出し 出力
getopt -o '' -l long-a: -- --long-a foo --long-a 'foo' --
getopt -o '' -l long-a: -- --long-a --long-a --long-a '--long-a' --
getopt -o '' -l long-a: -- --long-a=foo --long-a 'foo' --

省略可能なオプション引数

省略可能なオプション引数は、オプション名の最後に :: をつけることで指定します。オプション引数はショートオプションにつなげて渡すか、ロングオプションに = でつないで渡します。(スペースで区切って渡すことはできません。)

呼び出し 出力
getopt -o a::b -- -a -b -a '' -b --
getopt -o a::b -- -a foo -b -a '' -b -- 'foo'
getopt -o a::b -- -afoo -b -a 'foo' -b --
getopt -o '' -l long-a::,long-b -- --long-a --long-b --long-a '' --long-b
getopt -o '' -l long-a::,long-b -- --long-a foo --long-b --long-a '' --long-b -- 'foo'
getopt -o '' -l long-a::,long-b -- --long-a=foo --long-b --long-a 'foo' --long-b --

オプションとオプション以外の混在

GNU 版の getopt ではオプションとオプション以外を混在しても処理しやすい形に並び替えてくれます。途中でオプションとして -- 見つかった場合はそこで並び替えを中断します。この機能を無効にしてオリジナル版の getopt と同じ動きにするためには、オプション文字列の最初に + を置くか、POSIXLY_CORRECT 変数を定義します。

オプション文字列の先頭を - にすると、オプションでない引数は(-- の後ろのまとめられるのではなく)そのままの位置になります。(結合されたショートオプションの分解だけを行いたい時に使う?)

呼び出し 出力
getopt -o abc -- -a foo -b bar -c -a -b -c -- 'foo' 'bar'
getopt -o +abc -- -a foo -b bar -c -a -- 'foo' '-b' 'bar' '-c'
getopt -o -abc -- -a foo -b bar -c -a 'foo' -b 'bar' -c --
getopt -o abc -- -a foo -b -- bar -c -a -b -- 'foo' 'bar' '-c'
getopt -o abc -- -abc foo -b bar -c -a -b -c -b -c -- 'foo' 'bar'
getopt -o '' -l long -- --long=foo --long 'foo' --

単一の - で始まるロングオプション

-a または --alternative オプションを指定すると有効になります。find コマンドで使われてる形式のオプションですね。(例 find . -name "*.txt"- で始まるロングオプションは -- で始まるロングオプションに整形されます。

呼び出し 出力
getopt -o cetux -l exec -- -exec echo -e -x -e -c -- 'echo'
getopt -o cetux -l exec -a -- -exec echo --exec -- 'echo'
getopt -o cetux -l exec -a -- --exec echo --exec -- 'echo'
getopt -o cetux -l exec -a -- -execute echo -e -x -e -c -u -t -e -- 'echo'
getopt -o 'c:e:t:u:x:' -l exec -a -- -exec echo --exec -- 'echo'
getopt -o 'c:e:t:u:x:' -l exec -a -- -execute echo -e 'xecute' -- 'echo'

使用方法

ロングオプションなどの機能が追加されているだけで、使用方法はオリジナル版の getopt と殆ど変わりません。getopts に比べるとロングオプションが使えるなど機能は増えましたが、getopts のシンプルさはなくなりました。

# 位置パラメータへの設定
args=$(getopt -o a:b -l long-a:,long-b -- "$@") || exit 1 # $@ を使うこと。$* では空白を正しく扱えない
eval "set -- $args" # オリジナル版と違いクォートでくくられるので eval する必要がある

# オプション解析のためのループ
while [ $# -gt 0 ]; do
  case $1 in
    -a | --long-a) A_VALUE=$2; shift 2 ;;
    -b | --long-b) B_FLAG=1; shift ;;
    --) shift; break ;;
  esac
done

実際に書いてみるとすぐに気づくと思うのですが、ロングオプションの数が多くなると getopt の引数は長くなり case の部分とニ箇所に同じオプションを書かなければなりません。これは getopt が引数を整形する機能しかないからです。実際の引数の解釈は別の case で行わなければなりません。ショートオプションだけならまだマシですが、ロングオプションが増えてくると大変になってきます。

なお Ubuntu 18.04 の man getopt より使用例が書かれたファイルがあることがわかるのですが、正しいパスは /usr/share/doc/util-linux/examples/getopt-parse.bashgetopt-parse.tcsh)でした。


(ba)sh と (t)csh での使用例のスクリプトは、 getopt(1) ディストリビューションで提供されている。
これらはオプションとして /usr/local/lib/getopt または /usr/lib/getopt にインストールされている。

まとめ

以上、getoptgetopts について徹底的に解説してみましたが、結局私は使わないんですよね・・・。以下が私の方針です。

  • オリジナル版(BSD版)の getopt は使用しません。
  • ショートオプションだけの簡単なものであれば getopts を使用します。
  • ロングオプションやその他の機能が欲しくなったら独自実装します。
  • GNU版の getopt は特定の環境だけで動けばよく簡易なものを手っ取り早く作りたいときには使うかもしれません。

独自実装のオプション解析コード

getopt, getopts を使用しない独自実装のオプション解析コードについては 「高機能で短いシェルスクリプト用のオプション解析コード(POSIXシェル準拠・独自実装) 」を参照してください。

関連リンク

42
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
40