まず、質問をします。 IT-shnikovのコミュニティを見ると、美しいグラフィカルインターフェイスを備えたプログラムが豊富にあるにもかかわらず、コマンドラインアプリケーションが非常に人気があることがわかります。 なんで?
いくつかの答えがあります。 まず、
Unixの哲学は、多くの場合、それぞれ独自の特定のタスクを実行できる多くの小さなユーティリティが、1つの多機能ユニバーサルプログラムよりも優れているという原則に基づいています。 そして、これは、IT-shnikovの世界でUnixシステムが成功した理由の1つです。
おそらく、誰もがGUIからCLIに普通のユーザーを引き付けることができるとは考えにくいことを理解しており、「コンピューターサイエンティスト」という私たちに焦点を合わせて、CLIアプリケーションに対する希望を明確にしましょう。
一般的な要件
簡単に言えば、それらを単純に、しかし効率的に使用したいのです。 David Copelandは、これを達成するためのアプリケーション要件の包括的なリストを作成しました。
- 使いやすい-使いやすく、明確な目的を持つ必要があります。 できれば1つ。 トゥーラは、誰もがスイスのナイフの使い方を知っていますが、通常は使いづらく、その能力をすべて知っている人はいません。 ただし、多機能アプリケーションを設計して、使いやすく、サポートしやすくする方法についても説明します。
プログラムでの作業を簡素化するためにできる最小限のことは、オプションの形式に関する規則に従うことです。 ユーザーに再学習を強制しないでください! オプションを指定するのが慣例であり、それらに名前を付ける方法について詳しく説明します。 - 役立つ-これは、ユーザーがアプリケーションの実行方法、起動方法、構成方法に関するヘルプに簡単にアクセスできることを意味します。 アプリケーションがそのページをmanに追加することをお勧めします。 さらに、チーム完了レベルでのシェルとの統合は問題ありません。
- 他のユーザーとうまくやり取りする-アプリケーションは他のアプリケーションと対話できる必要があります。 これは、Unixで一般的なアプリケーションのモジュール性を意味します。 リターンコード、入出力ストリームでの思慮深い作業などを無視しないでください。
- 賢明なデフォルトがありますが、構成可能です-標準の使用シナリオは、千のオプションを指定せずに利用可能です。 カスタムシナリオは使いやすい必要はありませんが、手頃な価格である必要があります。 さらに、デフォルトのオプションセットはカスタマイズ可能にする必要があります。
- 簡単にインストール-すべての依存関係とともに簡単にインストールでき、起動を容易にするためにアプリケーション変数を環境変数に設定します。 更新も同様に簡単に行われます。
- 正常に失敗する-アプリケーションの呼び出しでエラーが発生した場合、エラーの内容と修正方法を報告する必要があります。 さらに、アプリケーションは非破壊的でなければなりません。 引数でエラーが発生した場合(および、理想的には、確認なしで危険な操作をまったく実行しない場合)、ファイルを上書きまたは消去しないでください。
- 新機能とバグ修正を簡単に取得-アプリケーションをサポートする必要があります。 アプリケーションをモジュールに分割し、それらを異なるファイルに分散します。 テストを書きます。 セマンティックバージョニングを使用します。 バージョン管理システムを使用します。
- ユーザーを喜ばせる-アプリケーションの出力は目に優しいはずです。 あなたの自由な色で、書式設定(たとえば、表形式またはhtml)。 インタラクティブなユーザーインタラクションも含まれます。
次に、これらのポイントについてさらに詳しく説明します。
使いやすい
ユーティリティとソフトウェアパッケージ。 どちらが便利ですか?
そのため、すべてのアプリケーションは、ユーティリティとソフトウェアパッケージ(元のコマンドスイート)の2つのタイプに条件付きで分割できます。
最初のタイプは、1つの目標と1つの操作モードを持つアプリケーションです。 このタイプのプログラムには数え切れないほどの例があり、ほとんどすべてのUnixコマンドは次のとおりです:ls、grep、diff、... さらに、連続処理のためにチェーンに接着するのが簡単です。 ここでは、次の例えが関係します。 あなたが家を建てていると想像してください。さらに、その家は標準モデルではありません。 モノリシックブロックからではなく、レンガから構築する方がはるかに便利です。場所によってはこれらのブロックをファイルする必要があり、どこかで石でジョイントを閉じる必要があるためです。 はい、ブロックはクレーンでしか引っ張ることができませんが、レンガは手で置くことができます。
2番目のタイプのプログラムは、スイスのナイフまたはフードプロセッサーと比較できます。 時には非常に便利です。 gitを見てください(ruby、gem、rails、bundleの世界ではすぐに記憶されます)-1つのプログラムですが、それをいくつ実行できますか。 そして、彼女はコミット/チェックアウトでき、自分で履歴を検索し、ファイル間の変更を検討します。 そのため、grep、diffなどが組み込まれています。Gitに何も組み合わせる必要はありません。彼はすべてを行う方法を知っています。 家との類推に戻ると、gitaにはあらゆる場面で標準的なプロジェクトがあります(そして、それらすべてを思い出そうとします)。
それでも、すべてのプログラムが多機能である必要はありません。すべて同じように、すべてのユースケースを実行するわけではありません。 この論文をサポートするために、cd、ls、pwd、diff、df、および便利な操作を1つのコマンドで実行できる「マルチツール」を想像することをお勧めします。オプションを少し変更するだけです(たとえば、ファイルシステムの変更、ファイルシステムの表示、 ) 使いますか? 私はあなたが過度のかさばりのために捨てると思います。 ソフトウェアパッケージは非常に便利ですが、8つの触手でケンタウロスを書く前に慎重に考えることは理にかなっています。
ところで、多数のユーティリティを作成し、それをソフトウェアパッケージにしたい場合は、修正するのはそれほど難しくありません。 コマンドをルーティングするラッパーを作成するだけです。 知らないかもしれませんが、gitはコマンドの種類に基づいてgitコマンドが制御を転送するgit-commit、git-show、git-hash-object、git-cat-file、git-update-indexなどの多数のユーティリティで構成されていますオプション(もちろん、ユーティリティ呼び出しの単一チェーンが1つのコマンドの背後にある場合があります)。 そのため、将来結合する小さなプログラムのセットで大規模なプロジェクトを開始することをお勧めします。 作成、デバッグ、保守、使用が簡単です。
コマンドライン引数の構文または「この家には独自の伝統があります。」
用語から始めます。 コマンドラインアプリケーションを起動するときに、いくつかのパラメーターセットを指定します。 それらは次のタイプに分けられます:オプションと引数。 David Copelandは、オプションをさらに2つのサブタイプ(フラグとスイッチ)に分割します。
概略的には、次の
executable [options] <arguments>
としてこれを表すことができ
executable [options] <arguments>
。 すべてが最新であると思いますが、念のため、角括弧内のパラメータはオプションであり、山括弧内のパラメータは必須であることを説明します。
引数(または位置引数)は、プログラムが機能するために指定する必要があるパラメーターです。 それらの順序は厳密に定義されています。
オプションはオプションのパラメーターです。 それらは任意の順序で指定できます。
スイッチタイプオプションはブールオプションであり、プログラムはその有無をチェックします。 例:--
--ignore-case
(または、
--ignore-case
--no-ignore-case
)。
フラグタイプオプションは、パラメータ付きのオプションです。 このパラメーターにはデフォルト値があります。 たとえば、私のバージョンでは
grep -C ...
と
grep -C 2 ...
場合、grepユーティリティは同等です。
引数とオプションの両方にデフォルト値がある場合がありますが、そうでない場合があります。
例として、
grep --ignore-case -r - 4 "some string" /tmp
引数は
"some string" /tmp
であり、オプションは
--ignore-case -r - 4
です。 同時に、
--ignore-case
と
-r
はスイッチであり、
-C 4
はフラグです。
オプションの規則
オプションは、短い
-i
形式と長い
--ignore-case
形式の両方で指定できます。 原則として、スクリプトのコマンドラインオプションを直接キャプチャできるため、オプション形式を好きなように楽しむことを妨げるものは何もありません。 しかし、Unixコミュニティによって開発されたルールを順守することをお勧めします。ルールは時を経て研ぎ澄まされ、ほとんどの人がそれに慣れています。 さらに、これらのオプションを簡単に操作できる既製のライブラリがあります。
これらのルールは次のとおりです。
- 長いオプション(
--long-option
)は2つのハイフンで始まり--long-option
。 オプション名にスペースを含めることはできませんが、単一のハイフンを使用できます。 - 短いオプション(
-l
)は、1つの文字(通常、大文字と小文字が区別されます)と先行するハイフン-l
構成されます。 短いオプションが長いアナログの最初の文字である場合、その意味を覚えやすくなります。 - 次のように、いくつかの短いオプションを組み合わせることができます
ls -a -l
ls -al
ls -a -l
同等です。 単一のハイフンの後、引数なしで必要な数のオプション - 短いオプションにパラメーターがある場合、通常はオプションの直後に置くか、スペースで区切ることができます。
-C4
または-C 4
「通常」と言ったのは偶然ではありませんでした。 そのため、たとえば、標準のoptparse rubyライブラリはこれら2つのケースを同じ方法で処理します。 lsユーティリティは、同様のオプションを同じ方法で処理します。 しかし、たとえば、grepユーティリティは、-C
分離され、4
が分離されていると見なします。 たぶんこれはバグです。 例外があることは言うまでもありませんが、プログラムが別の例外になった場合、ユーザーはあなたに感謝することはないでしょう。
-cxyz
は- xyz
と-c -x -y -z
両方として解釈できるため、短いオプションにデフォルト値(-c [param]
)の非数値パラメーターがある場合、通常どのように動作するのかわかりません。 オプションにオプションのパラメーターがある場合、ユーザーは常にスペースを書き込む方が適切です。 プログラマーは、オプションを一緒に記述することに関連する問題を最小限に抑える方法について事前に考える方がよいでしょう。 - 長いオプションの場合、パラメーターの前のスペースは通常許可されますが、等号を使用することをお勧めします。
ls --width=10
またはls --width 10
区切り文字がない場合、長いオプションの後、パラメーターは示されません(特にパラメーターが数値でない場合、どのような混乱が生じるかを自分で判断してください)。 - 各オプションは、短くても長くてもかまいません。 または、短いまたは長いだけがある可能性があります。 ただし、各オプションの長い形式の存在は非常に望ましいです。
- ブールオプションの場合、オプションの
no-
プレフィックスを指定できます。たとえば、--[no-]pager
。 --pagerオプションはページネーションを設定します。--no--no-pager
はページネーションがないことを示し、オプションがない場合はデフォルト値が保持されます。 これは、オプションがデフォルトで構成可能な場合に特に重要です。 たとえば、プレフィックスがなければ、オプションのデフォルト値を上書きすることはできません。
長い選択肢があることが常に推奨される理由
通常、オプションの長い形式は、アプリケーションを使用してスクリプトを記述する際に使用されます。 長いオプションは自己文書化する必要があります。 sysadminがcronを調べて、理解できないオプション
-zsf -m 100
れるデータベースバックアップタスクの起動を確認したとします。 彼がスクリプトの作成者でない場合は、何を意味するのかを理解するために、彼は助けに潜り込む必要があります。 同意して、オプションのセット
--scheme --max-size 100 --gzip --force
は彼にもっと多くを伝え、時間を無駄にしないようにします。
さらに、めったに使用されないオプションの短いオプションを作成することは推奨されません。 まず、アルファベットのすべての行のオプションにそれらを費やすほど多くの文字がありません。 第二に、さらに重要なことは、短いオプションがないことで、このオプションは通常の操作では二次的または望ましくないことであり、単純にできるからといって軽率に使用しないでください。
そのため、頻繁に使用されるオプションは短いものと長いものの両方であり、めったに使用されないオプションは長いだけです。
単機能アプリケーションと多機能アプリケーションのコマンドラインオプションの違い
これらの2つのタイプのアプリケーションは、呼び出されたときに引数の順序がわずかに異なります。
最初のタイプのアプリケーションの場合、呼び出しは通常次のようになります。
executable [options] <arguments>
ソフトウェアパッケージの場合、形式はやや複雑です。
executable [global options] <command> [command options] <arguments>
この本の例を次に示します
git --no-pager push -v origin_master
--no-pager
は、任意のgitコマンドに適用できるオプションです。
--no-pager
git --no-pager push -v origin_master
は、pushコマンドに固有のオプションです。 グローバルオプションとコマンド固有のオプションは同じ名前を持つことができることに注意してください。 ただし、この場合、すべてのツールがそれらの処理に適しているわけではありません。たとえば、標準のOptionParser rubyライブラリは、オプションが満たされた場所を区別しないため、このタスクに対処しません。 ソフトウェアパッケージを作成する場合は、GLIライブラリをより適切に使用してください。
念のため、入力プログラムは技術的にはパラメーターの文字列ではなく、既に要素に分割されたパラメーターの配列を受け取っていることを読者に思い出させます。 ルビーでは、この配列は
ARGV
と呼ばれます。 私たちが直接または特別な図書館の助けを借りて働くのは彼と一緒です。 スペースで要素に分割されていないことに注意してください(そうでない場合、たとえば、スペースを含むファイル名にすることはできません)、シェルのルールはやや複雑です。 また、文字のエスケープとグループ化のための引用符の使用も含まれます。 パラメータ文字列をスクリーニング、接着、または配列にカットする必要がある場合、またはその逆の場合-標準シェルワードライブラリをご覧ください。 これらの目的のために、
String#shellescape
、
String#shellescape
、
Array#shelljoin
の3つのメソッドのみで構成されています。
rubyコミュニティでは、ほとんどのコマンドラインアプリケーションはOptionParserまたはそれに基づくライブラリを使用します。 構成に関するセクションで-もう少し学習したら、OptionParserを使用して作成したコードの例を示します。
役に立つ
使用するawesome_programプログラムを初めて見たときを想像してください。 経験豊富なユーザーとしては、恐らく
awesome_program --help
して、引数の順序、一連のオプション、および使用例を確認することを期待します。 プログラムをリリースするとき、最初に見たユーザーがおそらく最初に同じことをすることを覚えておいてください。したがって、
-h
、--
--help
オプションを用意しておいてください。 タイプOptionParserのライブラリを使用する場合、プログラムが指定した説明とともに認識するすべてのオプションのリストが、プロンプト行に自動的に追加されます。
ヘルプ行に加えて、拡張ヘルプを人で書くことは理にかなっています。 ただし、私の知る限り、rubygemsはmanでページを自動的に設定しません。 ただし、システムにインストールされたgemのマニュアルドキュメントページを表示できるgem-man gemがあります。
マニュアルを作成するには、難しいnroff形式のファイルを作成する必要があります。 タスクを簡素化するには、ronnコンバーターライブラリを使用します。これにより、ドキュメントページをより単純な形式で作成できます。 すべての準備ができたら、
gem man awesome_gem
使用して、ヘルプ行を確認できます。 または、
alias gem='gem man -s'
記述できます。 この場合、manコマンドはgem manコマンドに置き換えられ、gemのヘルプを探すことができます。 gem-manが処理できなかったリクエストに対して、通常のmanの対応するページへの自動リダイレクトが発生します。
あなた自身のマンチップを作ることを計画しているなら、本を見てください、これにより多くの注意が払われます。
ユーザーがコマンドを実行しやすくするために、シェルレベルでチームを自動補完することができます(すべてのシェルで機能するわけではありません)。 これにより、タブボタンを押して、コマンド名、ファイル名などを自動的に補完できます。 ユーザーはスペルミスをする可能性が低くなり、コマンドを書く時間を大幅に短縮できます。
タブ補完を行い、プログラム内のコマンドの履歴を保存するには(irbなどのプログラムの対話モードで)、rubyに組み込まれたreadlineライブラリを使用するだけで十分です。
gets
代わりに
Readline.readline
コマンドを使用して、入力したすべてのコマンドの履歴を自動的に保存できます。
タブ補完は次のように行われます。
Readline.completion_proc=(block)
が
Readline.completion_proc=(block)
メソッドに返されます。このメソッドは、既に入力されたテキストの行に追加可能な配列を返します。これがタスク全体です。 例:
Readline.completion_proc = proc { |input| allowed_commands.grep /^#{input}/ }
すでに実行中のプログラムのレベルではなく、シェルのレベルでタブ補完が必要な場合、これはやや複雑です。
.bashrc
をいじる必要があり
.bashrc
。
最初に、行
complete -F get_my_app_completions my_app
追加
complete -F get_my_app_completions my_app
これで、
my_app()[- ]
を入力してから
my_app()[- ]
を入力する
my_app()[- ]
に、
get_my_app_completions
関数が呼び出されます。 この関数は、可能な自動補完オプションを
COMPREPLY
変数に
COMPREPLY
ます。この変数は、シェルがユーザーに追加オプションを提供するために使用します。
.bashrc
この関数を定義する必要があります。 todoアプリケーションの本から例を示します。
function get_todo_completions() { if [ -z $2 ] ; then # COMPREPLY=(`todo help -c`) else # , $2 COMPREPLY=(`todo help -c $2`) fi } complete -F get_todo_completions todo
ここで、プログラムで次の動作を実装する必要があります(これは簡単な演習として残しましょう)。
1)コマンドラインで
todo help -c
を手動で入力すると、アプリケーションコマンドのリストが表示されます:list、add、complete、help(それぞれ独自の行にあります)
2)
todo help -c complete
、開始されたがまだ完了していないすべてのタスクのリストが表示されます(完全なコマンドを適用できるタスク)。
help -c [...]
はサービスコマンドです。その存在は簡単なヘルプで省略できます。 ユーザーが使用するのではなく、
.bashrc
スクリプトを使用することを前提としてい
.bashrc
。
このスクリプトでは、関数は既に入力されているものに基づいて、何を置換できるかをアプリケーション自体に尋ねます(これは
help -
オプションの後に渡されます)。 プログラムは、アプリケーションにこのような特別なパラメーターセットが与えられたときの状況を監視し、標準出力にすべてのオプションのリストを表示します(既に見たように)、そこから直接シェルスクリプト
COMPREPLY
送信され
COMPREPLY
。
この本の著者は、独自のGLIライブラリを使用しています。GLIライブラリは、このようなオプションセットを自動的に追跡します。 GLIの助けを借りずに、この機能を簡単に実装できます。 ご覧のとおり、ここには魔法はありません。
他の人とうまく遊ぶ
プログラム間の便利な相互作用の必要性の問題については議論しません。Unixで働いた誰もがこれがどれほど重要かを評価できます。 主な問題は、これを達成する方法です。
リターンコード
まず、リターンコードを使用します。 プログラムが正常に完了した場合-0、エラーが発生した場合-ゼロ以外のさまざまなリターンコード。 シェルスクリプトは、最後に完了したプログラムのステータスを
$?
変数から要求することにより、プログラムが正常に動作したかどうかを判断できるため、これは重要
$?
。 戻りステータスを返すために、rubyは
exit(exit_status)
メソッドを使用します。
さまざまなエラーにさまざまなリターンコードを割り当てると、自分のプログラムを使用する別のプログラムが問題を修正できるかどうか、および注意を払う価値があるかどうかを判断できる可能性があります。 プログラムの外では、プログラムが「クラッシュ」したかどうかが怖いかどうかを確認する方が良いでしょう。 異なるリターンコードは異なる例外クラスのようなものです。RAMがないという事実にエラーがあるか、ネットワークが一瞬消えただけで再試行する価値があります。 一部のプログラムは、いくつかのエラーにより同時にクラッシュする場合があります。 一度に複数の問題を報告する必要がある場合は、ビットマスクを使用します。 ネットワークには、どのエラーに対してどのリターンコードを使用するのが一般的かについての推奨事項があります。GNU (非常に一般的な)およびFreeBSD (非常に具体的な)サイトでそれについて読むことができます。 エラーコードを気にしたくない場合は、少なくとも最小限の努力をしてください-エラーが発生した場合、少なくともいくつかのゼロ以外の値を返します。 そうしないと、他のプログラムはあなたのプログラムが正常に動作したかどうかを知ることさえできません。
ところで、シェルスクリプトからだけでなく、rubyスクリプトからもプログラムを実行できます。 これを行うには、
Kernel.system
や
IO.popen
など、いくつかのオプションがあります
IO.popen
詳細については、ドキュメントをご覧ください。
system
を使用して別のプログラムを呼び出す場合、同様のシェル変数
$?
でその戻りコードを見つけることができます
$?
。
I / Oストリームとエラーストリーム。 パイプ
コマンドラインから起動されるプログラムの相互作用の主な方法はパイプです。 パイプは、あるプログラムの出力を別のプログラムの入力にリダイレクトする方法です。 縦棒でマークされたパイプ
|
。 たとえば、
ls | sort
ls | sort
、最初の部分-lsは画面に何も表示しませんが、代わりにその出力をsortプログラムの入力にリダイレクトします。 また、ソートプログラムは入力ストリームからテキストを1行ずつ取得し、すでにソートされたリストが画面に表示されます。 一方では、ls自体がファイルをソートできますが、これは意図されていません。 同時に、ソートはこの目的のためだけに必要であり、多くのオプションがあります。 たとえば、名前が数字で始まる場合は、辞書式ではなく行を並べ替えることができます(そうでない場合、順序は1.jpg、10.jpg、100.jpg、2.jpg、...のようになります)。 または、逆の順序で並べ替えます。 さらに、特別なプログラム(awk、sedなど)を使用して、文字列を並べ替える前に、それを修正できます(たとえば、プレフィックスを消去します)。 パイプは任意の数のプログラムで構成できることに注意してください。 だから
ls | sort -n | tail
ls | sort -n | tail
ls | sort -n | tail
は、番号順にソートされたファイルのリストの最後の10行を表示します。
プログラムで入出力ストリームが必要になる理由を考えてください。 出力ストリームに書き込む内容、およびエラーストリームに書き込む内容。 最初に2番目の質問を扱います。出力ストリーム(stdout)とエラー(stderr)の違いは何ですか? 1つのスレッドがパイプに接続し、もう1つのスレッドが接続しないという事実。 stderrストリームは、エラーの出力だけでなく、プログラム実行の段階、デバッグ情報など、ワークプロセスに関する情報の出力にも使用されます。 この情報は、別のプログラムの入力に渡されるべきではなく、ユーザーの便宜のためにのみ必要です。 stdoutストリームは、プログラムの結果など、他のすべての情報に使用されます。
人だけでなく、マシンもプログラムの出力を処理する必要があるため、出力形式について考える必要があります。 オプション
--format=<plain|csv|pretty|html|table|...>
を作成するのは理にかなっています。 人間が読める形式(pretty / html / table)を指定する場合、出力の解析の利便性を考慮せずに、目を楽にする方法で情報を表示できます。 機械可読形式(plain / csv)を指定する場合、結果が美しく見えるかどうかは関係ありません-主なことは、解析を容易にすることです。 構文解析の利便性のために、タブ区切り値またはコンマ区切り値(csv)を使用するか、形式は1行-値、または最適な別の形式です。 また、Delight Usersセクションで、できる限り快適な結論を出す方法についても説明します。
ユーザーは、プログラムを起動するたびに出力形式を指定したくないため、すべての場合に選択することも常に可能とは限りません。 出力が人の目か機械の目かを自動的に判断するトリック、つまり
IO#tty?
メソッドはあり
IO#tty?
。
$stdout.tty?
出力が端末に向けられているかどうかを教えてくれます。 そうでない場合、プログラムの出力はパイプに
ls > output.txt
れるか、ファイルにリダイレクトされます(次のように:
ls > output.txt
)。 端末への出力とリダイレクトされたストリームへの出力では、異なるデフォルトのフォーマット
options[:format] = $stderr.tty? ? 'table' : 'csv'
選択できます
options[:format] = $stderr.tty? ? 'table' : 'csv'
options[:format] = $stderr.tty? ? 'table' : 'csv'
また、たとえば、人向けの出力形式でファイルに結果を出力する場合は、形式を明示的に指定するだけです。
次に、入力ストリームについて説明します。 プログラムは入力ストリームからどのようなデータを受け入れるべきですか? もちろん、これはプログラムの詳細に依存します。 考えてみましょう、どのデータを入力ストリームに入れることができますか? 明らかな答えは、他のプログラムが出力に持っているものです。 たとえば、マトリックスファイルを別の形式に変換し、別の拡張子を持つファイルに書き込むプログラムがあります。 入力ストリームから行列を受け入れることは理にかなっていますか? 私の意見では、そうではありません。この行列がどのように、そしてなぜ入力ストリームに入るのでしょうか? 一度に多くのファイルを処理するために、多数のファイル名を受け入れる方がはるかに便利です。 これは、たとえばlsコマンドが提供できるデータです。
, , . -, . , , , (, — — Windows-). , , . , .
, ,
$stdin.tty?
, , ( ) — . , , -, , . ( SIGHUP), , , , . SIGINT, Ctrl+C.
Signal.trap
. , , . ( , ) POSIX-, .. Unix, Windows. , , Windows , Unix, - , — , .
— , , Ctrl+C , , :
Signal.trap("SIGINT") do FileUtils.rm output_file exit 1 end
Has sensible defaults but is configurable
, . , - . , -- .
. , — -.
, . , ( ), . , . , — , . (
--use-nonstandard-mode
-u
).
. « -- »? , . , . - (,
--no-scheme --gzip
),
db_backup my_db
.
, .
db_backup --scheme my_db
, . , , , , -…
--login
,
--password
,
--host
,
--force
, , -. , , - .
~/.myapp.rc
. , . -. — . — . .rc — .
? , . YAML. :
--- :gzip: false :force: true :user: "Bob" :password: "Secr3t!"
, .
require 'yaml' require 'optparse' # - options = { :gzip => true, :force => false } # # ( , HOME) CONFIG_FILE = File.join(ENV['HOME'],'.db_backup.rc.yaml') if File.exists? CONFIG_FILE # config_options = YAML.load_file(CONFIG_FILE) # - options.merge!(config_options) end # # , option_parser = OptionParser.new do |opts| # . #__FILE__ , opts.banner = "Usage: #{__FILE__} [options] <db_name>" # -u --username , opts.on("-u USER", "--username", "Database username, in first.last format") do |user| options[:user] = user end # , opts.on("-p PASSWORD", "--password", "Database password") do |password| options[:password] = password end # , . , . # --gzip true. # , - # false --no-gzip opts.on("--[no-]gzip", "Compress or not the backup file") do |gzip| options[:gzip] = gzip end end # , option_parser. # ARGV , # options # ( ) option_parser.parse!(ARGV) # db_name = ARGV.shift
— . , — .
--- :filename: ~/.todo.txt :url: http://jira.example.com :username: davec :password: S3cr3tP@ss :commands: :new: :f: true :group: Analytics Database :list: :format: pretty :done: {}
, YAML — . , — . , , gem rspec, git.
Installs painlessly
, . , rubygems — , :
gem install/update gemname
— , , , , ( ). - rubygems.org . , , (, , ) gem .
gem install
, rubygems , ( ) . , , , ( -, ). , . , rails 2.3.8 rails 3.2, activesupport-, , .
, , , — . , , ruby .
, . « ». : Major.Minor.Patch. — - . API, -. , . , , , : 1.13.2.
, , - minor-. , , , . , API, .
— . , bin , ( bundler -). .../ruby/bin - ( , -, , ). , ruby PATH — . .
Windows , , — bat-, . , .
?
-, -, .rb. Unix, Windows. , .
-, :
#!/usr/bin/env ruby
,
/usr/bin/ruby
.
env
, , rvm.
-, , lib/my_exec.rb, require. , . :
#!/usr/bin/env ruby require 'rubygems' # ruby 1.9 require 'your-gem' require 'your-gem/my_exec'
, -? , , . ,
my_app value1 value2
. ? ,
['value1', 'value2']
. ? Unix , . Windows , ..
my_app
Windows, , ( ruby.exe). , , , ruby. つまり :
ruby my_app value1 value2
, ruby, , .
, , rubygems bat-? bat- , . rubygems . : . Hello World . , , ( , Windows- , Unix-). , , , rspec. git- ( , ruby). , Windows, - — .
Fails gracefully
.
. stderr , (, , ). , . - , .
- , , ? , , . , ,
--force
. , .
? , .
rm -rf * .log
, , , .
Gets new features and bug fixes easily
— , . , , . , . , , . …
, , ( ) . , , . ( HDD — ). - .
— aruba , Cucumber CLI. , , , , , - .
( ) — TestUnit rspec- fakefs . , , — , , . mock- ,
File
,
Dir
( ) , , . . 美人! , ( ,
Kernel.system
, ) lib/my_exec .
, aruba, , ? stdout stderr
StringIO
. «». :
out, err = MiniTest::Assertions.capture_io{ ... }
, , .
! -:
STDOUT
$stdout
. StringIO, , . , warning, , . ,
puts
- , .
, (
STDOUT.puts 'smth'
), , ,
STDOUT
,
STDIN
STDERR
.
. , .
ARGV
. , , ? : . shellwords
String#shellsplit
.
, , , ,
ARGV
:
ARGV.replace(new_array)
.
,
OptionParser#parse!
。
ARGV
OptionParser#parse!(new_array)
, ,
ARGV
. , — .
— . . .
Delights users
.
テーブル
, : , , , . : . — terminal-table .
色
, . . : /. - . — rainbow term-ansicolor . , . , — — . Windows- , . , .
, 10% . , , . diff , . , , , .
! machine-readable — , . , , « » .
. Readline, . , : . rubygems thor , say ask.
? irb rails console. : , JSON- , . JSON, cd, ls, rm mknode. , . .
, , . , , . : ? ? , ? , , stderr - ( , ,
flush
, - , ).
! , .
\r
— .
\r
, (, «» ). ,
puts
, .. .
print
, :
(0..100).each do |i| $stderr.print("\r#{i}% done") sleep(0.1) end
, , : stderr stdout , , .
.
-, rake , thor . — , DSL , .
Rake — make ruby. Rakefile . , bundler Rakefile : build, install, release, . rake — rake release build release. , rake , . , , rake.
Thor — rake. «» . .
, , . . , Ruby on Rails , , .
OptionParser ruby. , . , , — , . , OptionParser , ( — . ) .
OptionParser : ( ; , , , git). OptionParser- ( , ) — . , , — .
GLI . , . .
, , — docopt . — , , OptionParser . python . . , , .
PS , , ,
ARGF
. — ,
ARGF
— .