web-dev-qa-db-ja.com

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

アプリケーションの開発中に、疑問に思い始めました-コマンドライン引数をどのように設計すればよいですか?

多くのプログラムがこの-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に適格です(既存の質問を回答で変換できるかどうかはわかりません)。この質問をオペレーティングシステムやプログラミング言語に依存しないようにしたいので、ここに表示される回答は他の開発者にとって貴重な教訓になる可能性があります。

195
Filip Hazubski

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

  • 常に_--version_および_--help_を処理します(_/bin/true_でも受け入れられます!!)。 _--help_を理解していないソフトウェアの作者をののしりました。嫌いです(_prog --help_は最初のコマンドなので、新しいプログラムに取り組んでいます)。しばしば_--help_は_-h_と省略できます

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

  • _-a_短い引数(1文字)を受け入れ、同等の_--long-argument_をいくつか持つため、_-a2_ _--long-argument=2_、_--long-argument 2_;もちろん、(ほとんど使用されないオプションの場合)_--only-long-argument_の名前を付けることができます。余分なオプションのないモーダル引数の場合、_-cf_は通常_-c -f_などとして処理されるため、_-argument:value_の提案はおかしいので、お勧めしません。

  • gLIBCを使用 getopt_long 以上(例 argp_parse 、OCamlでは Arg module 、...)

  • 標準入力または出力に_-_をよく使用します(それができない場合は、_/dev/stdin_および_/dev/stdout_を、それらを持たないいくつかのオペレーティングシステムでも処理します)。

  • ほとんどのオプションの規則を再利用することにより、同様のプログラムの動作を模倣します。特に、ドライランの場合は_-n_(àmake)、ヘルプの場合は_-h_、詳細度の場合は_-v_など...

  • オプションとファイルまたは他の引数の間の区切り文字として_--_を使用します

  • プログラムがisattyを使用してstdinよりもテストする場合(およびその場合は「対話式」に動作します)、プログラムに次のように、非対話モードを強制するオプションを提供しますGUIインターフェイス(およびX11デスクトップでgetenv("DISPLAY")をテスト)。ただし、バッチまたはコマンドラインで使用することもできます。

  • 一部のプログラム(例:gcc)は間接引数リストを受け入れるため、_@somefile.txt_は_somefile.txt_からプログラム引数を読み取ることを意味します。これは、プログラムが非常に多くの引数(カーネルの_ARG_MAX_よりも多い)を受け入れる可能性がある場合に役立ちます。

ところで、プログラムや通常のシェル(bashzshなど)にオートコンプリート機能を追加することもできます

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

ソフトウェアが関連する一連のコマンドラインプログラムである場合、_git help_と_git --help_を受け入れて git (開発ツールとして使用する)からインスピレーションを得て、多くのgitsubcommandおよびgitsubcommand _--help_

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

POSIXではShellglobbing 引数(beforeプログラムの実行!)であることを忘れないでください。したがって、(_*_またはシェルエスケープする必要があるオプションの_$_または_~_)。

場合によっては、ソフトウェアに GNU guile または Lua のようなインタープリターを埋め込むことができます(独自の Turing-complete スクリプト言語を発明することは避けてください)プログラミング言語の専門家ではありません)。これはソフトウェアの設計に深い影響を与えます(そのため、早い段階で考えるべきです)。そうすれば、そのインタプリタにスクリプトや式を簡単に渡すことができるはずです。その興味深いアプローチを取る場合は、ソフトウェアとその解釈済みプリミティブを注意深く設計してください。奇妙なユーザーがあなたの事物のために大きなスクリプトをコーディングするかもしれません。

他のケースでは、上級ユーザーが プラグイン をソフトウェアにロードできるようにすることもできます( 動的ロード テクニックàla dlopen)を使用dlsym)。繰り返しますが、これは非常に重要な設計上の決定です(したがって、プラグインインターフェイスを慎重に定義して文書化してください)。これらのプラグインにプログラムオプションを渡すための規則を定義する必要があります。

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


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


追伸可能であれば、プログラムを フリーソフトウェア にすると、一部のユーザーや開発者から改善が得られます(多くの場合、新しいプログラムオプションの追加は、既存のフリーソフトウェアに追加する最も簡単な方法の1つです)。また、質問はたくさん対象読者によって異なります:ティーンエイジャー向けのゲームやおばあちゃん向けのブラウザはおそらく必要ありませんコンパイラ、データセンターのシステム管理者向けのネットワークインスペクタ、またはマイクロプロセッサアーキテクトやブリッジデザイナ向けのCADソフトウェア)と同じ種類と量のオプション。おばあちゃんよりも多くの調整可能なオプションがあり、おそらくX11なしでアプリケーションを実行できるようにしたい場合があります(おそらくcrontabジョブで)。

239

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

=または:または ''を区切り文字として使用しても、わずかな労力でコンピューターによって相互に変換できる些細な違いであることが簡単にわかります。 bigの取り組みとは、人間が覚えていることです。「さて、このあまり使用されないプログラムが:または=?うーん...」

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

69
Kilian Foth

簡単に言えば

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

  • 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ではparameter auto-completionを追加することを忘れないでください。つまり、ユーザーはスイッチの半分を入力してTABを押すと、シェルがそれを完了します。
29

まだ思いつかなかったことの1つ:

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

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

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

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

docoptは、特にpythonが非常に制限されており、argparseのようなユーザーに悪影響を与える引数パーサーが「OK」と見なされている場合)において、多くの言語でこれに非常に役立ちます。パーサーとサブパーサーの代わりに条件付きディクテーションでは、構文ヘルプを定義するだけで、あとは残ります。

19
Florian Heigl

いくつかの貴重なコメントはすでに提供されていますが(@ 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's Shelldorado によって提供されるガイダンスと、言及されている他のリファレンスを常に念頭に置いてきました。

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

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

このアプローチで使用されるクラシックツールセットは Tcl/Tk です。ツールの切り替えは提案していません。最初に、GUIベースの管理アプリをコマンドラインツールとしてアプリに書き込むことから、設計アプローチを検討してください。次に、便宜上、GUIを上に重ねます。複数の構成を行い、一般的に同じオプションを何度も再入力する必要がある場合、GUIが面倒(そしてエラーが発生しやすい)であることに気づくでしょう。自動化されたアプローチを探します。

いずれにしても、管理者は正しいボックスに正しい値を入力する必要がある可能性があるため、GUIを使用して、どれほどの労力を軽減できますか?

3
Ian W