コマンドライン引数を設計するための良い習慣は何ですか?


190

アプリケーションの開発中、私は疑問に思い始めました-コマンドライン引数をどのように設計する必要がありますか?

プログラムの多くは、このように式を使用しています-argument value/argument value。私の頭に浮かんだ解決策はargument:value。空白がないと、値と引数を台無しにする方法がないので、良いと思いました。また、左の:文字から最初の文字列を2つに分割するのは簡単です。

私の質問は:

  1. 人気のある-argument value式はargument:value、より読みやすく、書きやすく、バグがなく、専門の開発者が理解しやすいですか?
  2. コマンドライン引数を設計する際に従うべき一般的に知られているいくつかのルールはありますか(動作する場合は問題ありません)?

詳細を尋ねられたので提供します。ただし、回答に影響を与えるべきではないと思います。質問は一般的に良い習慣についてです。それらはすべての種類のアプリケーションで同じだと思います。

私たちは、公共の場所(タッチトーテム、テーブル)で使用されるアプリケーションに取り組んでいます。アプリケーションは、Qt Quick 5(C ++、QML、JS)を使用して記述されています。デバイスにはWindows 8.1 / 10がインストールされます。デバイスを管理するためのフロントエンドインターフェイスを提供します。ただし、一部の上級管理者は、自分でアプリケーションを構成することができます。ビジネスの観点からはそれほど重要ではありませんが、Kilian Fothが言ったことに同意するように、自分のアプリケーションがユーザーの苦痛になりたくないのです。私がここで尋ねたものをインターネットで見つけられない。


より高度なStack Exchangeユーザーへ:この質問を一般的なものにしたかった。コミュニティWikiに該当する可能性があります(既存の質問を回答で変換できるかどうかはわかりません)。この質問をオペレーティングシステムとプログラミング言語に依存しないようにしたいので、ここに表示される答えは他の開発者にとって貴重な教訓になります。


14
人気のあるコマンドラインツールをご覧ください。たとえば、多くの場合、単一のハイフンを使用してオプションを組み合わせます。例えば、あなたが書くかもしれないls -ltrオプションを組み合わせること-l-tおよび-r。GNUスタイルのプログラムでは、通常、の--reverse代わりに二重ハイフンを使用した単語ベースのオプションも許可されます-r-hヘルプを表示したり、--オプションの終了を通知し-たり、stdinからの読み取りを許可するファイル名として指定したりするなど、その他の一般的な規則があります
。– Brandin

72
どちらも一般的ではありませ-argument value-argument:value。共通するのは、ある-a value-avalue--argument=value
reinierpost

39
getopt(s)可能な場合は、一般的なコマンドライン解析ライブラリ(通常はのようなもの)を使用します。
reinierpost

5
@ k3b Qtで作業しています。ケビン・クラインはで言った彼のコメント我々はすでに利用可能なライブラリを使用することができます。マルチプラットフォームでよく考えられていると思います。QCommandLineParser
フィリップHazubski

11
最終的な宣伝文句の問題は、引数の解析がプラットフォームに依存しない問題ではないことです。
pydsigner

回答:


237

POSIXシステム(Linux、MacOSXなど)では、少なくともシェルターミナルで起動される可能性のあるプログラム(たとえばそれらのほとんど)については、GNUコーディング規則(一般的な引数名もリストします)を使用し、POSIXユーティリティガイドラインを調べることをお勧めします、プロプライエタリなソフトウェアでも:

  • 常に扱い--version--help(でも/bin/true、それらを受け入れる!!)。私は理解していないソフトウェアの作者を呪います--help、私は彼らを嫌います(なぜならprog --help 、私は新しいプログラムで試みている最初のコマンドだからです!)多くの--help場合、略すことができます-h

  • 持っている--help(あなたが最も一般的なものと、その場合リストに...それらのあまりに多くを持っていない限り、すべてのオプションのメッセージのリストを明示的には、いくつかを参照manし、オプションのデフォルト値ページまたは一部のURL)、そしておそらく重要な(とプログラム固有) 環境変数。オプション引数エラーでこれらのオプションリストを表示します。

  • 受け入れ-a短い引数(単一の文字)を、いくつか同等のものを持っている--long-argumentので-a2 --long-argument=2--long-argument 2。もちろん、(めったに使用されないオプションのために)何らかの--only-long-argument名前を持つことができます。追加のオプションのないモーダル引数の場合-cf、一般的-c -fになどとして処理されるため、あなたの-argument:value提案は奇妙であり、それを行うことはお勧めしません。

  • GLIBC getopt_long以上を使用します(例:argp_parse、OCamlではArgモジュール、...)

  • 頻繁に使用する-(あなたがそれを行うことができない場合、取り扱う標準入力または出力のために/dev/stdin/dev/stdoutさらにいくつかのオペレーティング・システム上でそれらを持っていません)

  • オプションの規則のほとんどを再利用することにより、同様のプログラムの動作を模倣します。特に-n、ドライラン(アラmake)、-hヘルプ、-v冗長性などのために...

  • --オプションとファイルまたは他の引数の間のセパレータとして使用

  • プログラムisattystdinがターミナルであるよりもテストするために使用する場合(およびその場合は「対話的に」動作する)、プログラムにGUIインターフェースがある(およびgetenv("DISPLAY")X11デスクトップでテストする)場合と同様に、非対話モードを強制するオプションを提供するバッチまたはコマンドラインで使用されます。

  • 一部のプログラム(例gcc)は間接引数リストを受け入れます。@somefile.txtつまり、プログラム引数をsomefile.txt; から読み取ることを意味します。これは、プログラムが非常に多くの引数(カーネルの引数を超えるARG_MAX)を受け入れる場合に便利です。

ところで、あなたのプログラムと通常のシェル(bashまたはのようなzsh)にオートコンプリート機能を追加することもできます。

いくつかの古いUnixコマンド(例えばdd、またはsed)には、歴史的な互換性のために奇妙なコマンド引数があります。私は彼らの悪い習慣に従わないことをお勧めします(あなたがそれらのより良い変種を作っているのでない限り)。

お使いのソフトウェアは、関連するコマンドラインプログラムのシリーズからインスピレーションを取る場合にはgitの受け入れ(あなたはきっと開発ツールとして使用)、git helpそしてgit --help、多くのを持っているgitsubcommandし、gitsubcommand--help

まれargv[0]に、(プログラムでシンボリックリンクを使用して)を使用することもあります。たとえば、異なる動作(制限されたシェル)bashとして起動されrbashます。しかし、私は通常、そうすることはお勧めしません。プログラムがshebangを使用するスクリプトインタープリターとして、つまりexecve(2)によって解釈される最初の行で使用できる場合、それは理にかなっているかもしれません。このようなトリックを行う場合は、メッセージを含めてそれらを文書化してください。#!--help

POSIXでは、シェルは(プログラムを実行する前に)引数をグロブしていることに注意してください。したがって、シェルエスケープする必要があるオプション(またはなど)の文字を要求しないでください。*$~

場合によっては、GNU guileLuaなどのインタープリターをソフトウェアに埋め込むことができます(プログラミング言語の専門家でない場合は、独自のチューリング完全なスクリプト言語を発明しないでください)。これは、ソフトウェアの設計に大きな影響を及ぼします(したがって、早期に検討する必要があります!)。そうすれば、簡単にスクリプトまたは式をそのインタープリターに渡すことができるはずです。その興味深いアプローチをとる場合は、ソフトウェアとその解釈されるプリミティブを慎重に設計してください。あなたはあなたのために大きなスクリプトをコーディングする奇妙なユーザーを持つことができます。

他の例では、あなたは、高度なユーザーが自分のロードせたいかもしれないプラグインを(使用して、ソフトウェアに動的ロードラà技術dlopen&をdlsym)。繰り返しになりますが、これは非常に重要な設計上の決定です(したがって、プラグインインターフェイスを慎重に定義および文書化します)。これらのプラグインにプログラムオプションを渡すための規則を定義する必要があります。

ソフトウェアが複雑な場合は、いくつかの構成ファイル(プログラム引数の追加または置換)を受け入れ、おそらくすべてのコードを実行せずにこれらの構成ファイルをテスト(または単に解析)する方法があります。たとえば、メール転送エージェント(EximやPostfixなど)は非常に複雑であり、「ハーフドライ」で実行できると便利です(たとえば、実際にメールを送信せずに特定のメールアドレスを処理する方法を観察できます)。


/optionはWindowsまたはVMSのものであることに注意してください。これは、POSIXシステムでは正気ではありません(ファイル階層が/ディレクトリセパレータとして使用するため、またシェルがグロビングを行うため)。私の答えはほとんどがLinux(およびPOSIX)に対するものです。


PS可能であれば、プログラムをフリーソフトウェアにします。一部のユーザーと開発者から改善が得られます(そして、新しいプログラムオプションを追加することは、多くの場合、既存のフリーソフトウェアに追加する最も簡単なものの1つです)。また、あなたの質問は対象となる視聴者に大きく依存ます。ティーンエイジャー向けのゲームやおばあちゃん向けのブラウザは、おそらくコンパイラ、データセンターのシステム管理者向けのネットワークインスペクタ、またはマイクロプロセッサ用のCADソフトウェアと同じ種類と量のオプションを必要としません建築家または橋梁設計者向け。プログラミングとスクリプティングに精通しているエンジニアは、おばあちゃんよりも多くの調整可能なオプションを持っていることを好み、おそらくX11なしで(おそらくcrontab仕事中に)アプリケーションを実行したいと思うかもしれません。


18
同意しましたgit が、より良い例です。私もお勧めしません探しcvs2016年
バジーレStarynkevitch

8
+オプションが無効な場合は、ヘルプを表示します。のような無駄なエラーメッセージを取得するのは面倒ですdd -h
-domen

8
GNUプログラム--helpは原則としてサポートしていますが、多くの場合、-hどれが迷惑かを認識しません。プログラムのオプションを忘れたときは、通常-hと入力します--help。長いオプションでコマンドを再入力するのは面倒です。結局、何かを忘れてしまったので、-hと入力しました。ヘルプ画面を表示するために、どのプログラムに「--help」が必要で、どのプログラムに「-h」が必要かを覚えておく必要があるのはなぜですか?-hと--helpの両方のオプションを含めるだけです。
ブランディン

30
この答えの最初の部分は良いですが、あなたのどこかに接線があります。たとえば、構成ファイル、プラグイン、dlopen、ソフトウェアライセンスの選択、Webブラウザは、実際にはコマンドラインインターフェイスの規則とは関係ありません。
ブランディン

5
そしてお願いします。画面の出力をフォーマットする場合は、出力フォーマットのオーバーライドを追加します。スクリプトでそれらを使用しようとするときに、行を切り詰めたり折り返すコマンド以外に私を悩ませるものはありません。
-Sobrique

68

データ形式の規則が一般的であるという事実、その利点です。

=または:または ''をセパレータとして使用することは些細な違いであり、コンピューターで簡単に変換できることは簡単にわかります。何だろう、大きな努力することは、人間が覚えておくためである、「この頻度の低い-使用するプログラムは、で物事を区切るやった、参照今:かと=?うーん...」

言い換えれば、神の愛のために、説得力のある理由なしに非常に定着した慣習から逸脱しないでください。あなたのプログラムは、「私の大学のエッセイを保存したもの」ではなく、「奇妙で迷惑なcmdline構文を持つもの」として記憶されます。


19
ほとんどすべての言語には、コマンドライン引数を処理するライブラリ関数があります。それらのいずれかを使用します。
ケビンクライン

9
良いアドバイスですが、それらの規則は何ですか?-1-
ラバーダック

14
この規則に意図的に違反する、よく使用されるUNIXツールの興味深い例があります。構文をdd使用しkey=valueます。この設計決定の理由は、このツール(ニックネーム:d ata d estroyer)を誤って使用すると、多くの損害を引き起こす可能性があるためです。ユーザーに通常の習慣を放棄させることにより、ユーザーは自分がしていることについてより密接に考えるように強制されます。
フィリップ

18
それが理由だと確信していますかdd?カーネルのARG_MAXが小さく、シェルに自動補完--long-argumentsがなく、存在しなかった時期(1970年代?)に単純にコーディングされたと思います。それ以来、dd下位互換性を維持したほうがよい
バジル・スタリンケビッチ

9
dd別のOS(UNIXより)-IBMのOS / 360上のスクリプト言語(JCL)-慣習が異なり、UNIXに多少変更せずに移植される前-使用する可能性が高いため、以前のシステム。
バールドコッペルード

29

素人の言葉で

ローマにいるときは、ローマ人と同じようにしてください。

  • CLIアプリがLinux / Unixを対象としている場合は、-p valueまたはの--parameter value規則を使用してください。Linuxには、このようなパラメーターとフラグを簡単な方法で解析するためのツールがあります。

私は通常このようなことをします:

while [[ $# > 0 ]]
do
key="$1"
case $key in
    --dummy)
    #this is a flag do something here
    ;;
    --audit_sessiones)
    #this is a flag do something here
    ;;
    --destination_path)
    # this is a key-value parameter
    # the value is always in $2 , 
    # you must shift to skip over for the next iteration
    path=$2
    shift
    ;;
    *)
    # unknown option
    ;;
esac
shift
done
  • CLIアプリがWindowsを対象としている場合、使用/flagおよび/flag:value規則。

  • ただし、Oracleなどの一部のアプリはどちらも使用しません。Oracleユーティリティはを使用しますPARAMETER=VALUE

  • 私がやりたいことの1つは、コマンドラインでパラメーターを受け入れることに加えて、長いパラメーターチェーンを回避するためのキーと値のペアファイルであるparfileを使用するオプションを提供することです。そのためには、追加の--parfile mifile.parパラメーターを指定する必要があります。を--parfile使用する場合、明らかに、他のすべてのパラメーターは破棄され、parfile内の内容が優先されます。

  • 追加の提案は、いくつかのカスタム環境変数の使用を許可することです。たとえば、環境変数MYAPP_WRKSPACE=/tmpを設定すると、常に設定する必要がなくなります--wrkspace /tmp

  • Linuxでは、パラメーターauto-completionを追加することを忘れないでください。これは、ユーザーがスイッチの半分を入力し、ヒットするTABと、シェルがそれを完了することを意味します。

1
さて、いくつかのGNUユーティリティ(例えばgcc@mifile.parはあなたの--parfile mifile.par提案のように処理します。
バジルスターリンケビッチ

7
パラメーターファイルがある場合、他のすべてのオプションを無視してもよろしいですか?せいぜい直感に反して聞こえます。
ジョナサンレフラー

8
パラメータファイルについてはJonathanに同意します。パラメータファイルが存在する場合、コマンドラインで指定された引数がparfileの引数の上に適用され、デフォルト値に使用されると予想されます。何らかの理由でparfileを使用すると、追加のコマンドライン引数を使用できない場合、追加の引数が存在するとエラーになります。
エルドリッチチーズ

@EldritchCheese私が書いたCLIアプリでは、parfileが指定されると、追加のパラメーターはエラーを生成します。
Tulainsコルドバ

1
有能なシェルを使用する場合、この種の「config file parameter」オプションは不要です。たとえば、あなたは書くだけfooCmd -opt1 -opt2 $(cat more_options.opts)です。したがって、「config file parameter」オプションが提供された場合、基本的に同じように機能するはずです。
ブランディン

19

まだ出てこなかったことが1つあります。

コマンドライン引数から上向きにソフトウェアを設計してください。意味:

機能を設計する前に、ユーザーインターフェイスを設計します。

これにより、エッジケースと一般的なケースを早期に掘り下げることができます。もちろん、外側と内側を抽象化しますが、すべてのコードを記述してからCLIを非難するよりもはるかに良い結果が得られます。

さらに、docopt(http://docopt.org/)を確認してください。

docoptは、多くの言語、特にargparseのようなユーザーに反する引数パーサーがまだ「OK」と見なされている場合に、Pythonで非常に役立ちます。パーサーとサブパーサーと条件付き辞書を使用する代わりに、構文ヘルプを定義するだけで残りは処理されます。


私は現在argparse、プログラマー、ユーザーインターフェース、ユーザーフレンドリーのいずれでもないことに不満を持っているため、この回答が大好きで、ありがとうございます。

私はdocoptを試しましたが、好きではありません。クリックすると、コードがずっときれいになりますが、サブコマンドがある場合はオプションが少し不自然になります。
jpmc26

2
これは広告のようなものです。関連性がある場合は、リソースに一度だけ言及してください。しかし、今のところ、答えの50%は外部リソースを宣伝するように聞こえます。
ブランディン

「最初に使用モデルを設計する」と言います。ユーザーエクスペリエンスを機能から分離することは、多くの場合、人為的な区別になる可能性があります(ツールの制限がインターフェイスに影響します)。
copper.hat

1
Docoptの場合は+1。CLIのすべてのジレンマを完全に痛みなく解決しました。真の熱意から広告を伝えるのが難しいこともありますが、ここではそうです-私は何年もDocoptの愛好家であり、いかなる形でも提携していません;)
frnhr

3

いくつかの貴重なコメント(@ Florian、Basile)が既に提供されていますが、私に付け加えてください... OPは言います、

デバイスを管理するためのフロントエンドインターフェイスを提供します。ただし、一部の上級管理者は、自分でアプリケーションを構成することができます。

ただし、次のことも注意してください。

この質問をプラットフォームや言語固有のものにしたくない

ターゲットオーディエンス(上級管理者)を考慮する必要があります。通常、どのプラットフォームで動作しますか-Win / Unix / Mac?アプリはどのプラットフォームで実行されますか?そのプラットフォーム用にすでに確立されているCLI規約に従ってください。「上級」管理者は、GUIベースのツールを必要としていますか、それとも必要ですか。

インターフェイスは、内部および他の管理ツールと一貫性が必要です。私は停止し、それだと思うしたくないcmd -p <arg>か、cmd -p:<arg>またはcmd /p <arg>。スペースがあるので引用符が必要ですか?私はできcmd -p <val1> <val2>またはcmd -p <val1> -p <val2>複数のターゲットのために?彼らは特定の注文ですか?オーバーロード可能?cmd -p2 <arg> -p1 <arg>あまりにも動作しますか?ls -l -r -t dir1 dir2== ls -trl dir1 dir2

Unix管理ツールについては、言及されている他の参考文献とともに、HeinerのShelldoradoが提供するガイダンスを常に念頭に置いています。

CLIを設計するのと同じくらい重要なのは、アプリケーションがGUIと同じコマンドライン引数で動作するように設計することです。つまり、GUIにビジネスロジックがないか、GUIとCLIの両方から呼び出される共通コマンドを使用します。

ほとんどのUNIXベースの管理ツールは、実際には最初にコマンドラインツールとして設計されており、提供されているGUIにより、コマンドラインのオプションを簡単に「入力」できます。そのアプローチにより、自動化、応答ファイルの使用など、およびハンドオフ管理が可能になります(私にとってはあまり手間がかかりません!)

このアプローチで使用される古典的なツールセットはTcl / Tkです。ツールを切り替えることを提案していません。GUIベースの管理アプリをコマンドラインツールとしてアプリに最初に記述することから、設計アプローチを検討してください。次に、利便性のためにGUIを上に重ねます。複数の設定を行い、一般的に同じオプションを何度も再入力する必要がある場合は、GUIが苦痛(およびエラーが発生しやすい)になることを発見する可能性があり、自動化されたアプローチを探します。

とにかく管理者が正しいボックスに正しい値を入力しなければならない可能性が高いことを覚えておいてください。


はい、素晴らしい!1つの質問もあります:./this
Florian Heigl
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.