少し前にすてきなRubyスクリプトを作成しました。適切な引数の数をチェックすることで、その堅牢性を改善したいと思います。
if ARGV.length != 2 then
puts "Usage: <command> arg1 arg2"
end
もちろん、それは擬似コードです。とにかく、CまたはC++では、argv[0]
または./myScript.rb
またはmyScript.rb
のように呼び出したかどうかにかかわらず、/usr/local/bin/myScript.rb
を使用して、ユーザーがコマンドにアクセスするために使用した名前を取得できます。 。 Rubyでは、ARGV[0]
が最初の真の引数であり、ARGV
にはコマンド名が含まれていないことを知っています。これを取得する方法はありますか?
Rubyには、呼び出されたスクリプトの名前を与える3つの方法があります。
#!/usr/bin/env Ruby
puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"
そのコードを「test.rb」として保存し、いくつかの方法で呼び出すと、スクリプトがOSから渡された名前を受け取ることがわかります。スクリプトは、OSがそれを伝えることのみを知っています。
$ ./test.rb
$0 : ./test.rb
__FILE__ : ./test.rb
$PROGRAM_NAME : ./test.rb
$ ~/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb
$ /Users/ttm/Desktop/test.rb
$0 : /Users/ttm/Desktop/test.rb
__FILE__ : /Users/ttm/Desktop/test.rb
$PROGRAM_NAME : /Users/ttm/Desktop/test.rb
2番目の例で$ HOMEの~
ショートカットを使用して呼び出すと、OSが3番目の例にあるものと一致する拡張パスに置き換えます。すべての場合において、OSが渡したものです。
ハードリンクとソフトリンクの両方を使用してファイルにリンクすると、一貫した動作が示されます。 test1.rbのハードリンクとtest2.rbのソフトリンクを作成しました。
$ ./test1.rb
$0 : ./test1.rb
__FILE__ : ./test1.rb
$PROGRAM_NAME : ./test1.rb
$ ./test2.rb
$0 : ./test2.rb
__FILE__ : ./test2.rb
$PROGRAM_NAME : ./test2.rb
スクリプト名のバリエーションを使用してRuby test.rb
を起動すると、一貫した結果が返されます。
呼び出されたファイル名だけが必要な場合は、Fileのbasename
メソッドを変数の1つと共に使用するか、区切り文字で分割して最後の要素を取得できます。
$0
と__FILE__
には若干の違いがありますが、単一のスクリプトの場合は同等です。
puts File.basename($0)
マイナーな追加:
メソッドのFile.basename
、File.extname
およびFile.dirname
スイートを使用することにはいくつかの利点があります。 basename
はオプションのパラメーターを取ります。これは、除去する拡張子です。したがって、拡張子なしのベース名のみが必要な場合
File.basename($0, File.extname($0))
ホイールを再発明したり、可変長や欠落している拡張機能を処理したり、拡張機能チェーン「.rb.txt
」を誤って切り捨てたりすることなく処理します。
Ruby-1.9.2-p136 :004 > filename = '/path/to/file/name.ext'
=> "/path/to/file/name.ext"
Ruby-1.9.2-p136 :005 > File.basename(filename, File.extname(filename))
=> "name"
Ruby-1.9.2-p136 :006 > filename = '/path/to/file/name.ext' << '.txt'
=> "/path/to/file/name.ext.txt"
Ruby-1.9.2-p136 :007 > File.basename(filename, File.extname(filename))
=> "name.ext"
この答えは少し遅れる可能性がありますが、私は同じ問題を抱えており、受け入れられた答えは私にはまったく満足のいくものではなかったので、もう少し調査しました。
気になったのは、_$0
_または_$PROGRAM_NAME
_がユーザーの持っているものに関する正しい情報を実際には保持していなかったという事実でしたtyped。 my RubyスクリプトがPATHフォルダーにあり、ユーザーが実行可能ファイル名(_./script
_や_/bin/script
_などのパス定義なし)を入力した場合、常に展開されます。合計パス。
これはRuby赤字だと思ったので、同じことをPythonで試してみました。
友人から_real thing
_で_/proc/self/cmdline
_を探すためのハックが提案されましたが、結果は_[Ruby, /home/danyel/bin/myscript, arg1, arg2...]
_(null-charで区切られています)でした。ここでの悪役はexecve(1)
であり、インタープリターに渡すときにパスをトータルパスに展開します。
Cプログラムの例:
_#include <stdlib.h>
#include <unistd.h>
extern char** environ;
int main() {
char ** arr = malloc(10 * sizeof(char*));
arr[0] = "myscript";
arr[1] = "-h";
arr[2] = NULL;
execve("/home/danyel/bin/myscript", arr, environ);
}
_
出力: `使用法:/ home/danyel/bin/myscript FILE ...
これが実際にexecve
であってbashのものではないことを証明するために、渡された引数を出力するだけで何もしないダミーインタープリターを作成できます。
_// interpreter.c
int main(int argc, const char ** argv) {
while(*argv)
printf("%s\n", *(argv++));
}
_
それをコンパイルしてパスフォルダーに入れ(またはフルパスをシェバンの後に置きます)、ダミースクリプトを_~/bin/myscript/
_に作成します
_#!/usr/bin/env interpreter
Hi there!
_
さて、main.cで:
_#include <stdlib.h>
extern char** environ;
int main() {
char ** arr = malloc(10 * sizeof(char*));
arr[0] = "This will be totally ignored by execve.";
arr[1] = "-v";
arr[2] = "/var/log/Apache2.log";
arr[3] = NULL;
execve("/home/danyel/bin/myscript", arr, environ);
}
_
_./main
_のコンパイルと実行:インタープリター/ home/danyel/bin/myscript -v /var/log/Apache2.log
この背後にある可能性が最も高い理由は、スクリプトがPATHにあり、フルパスがnotである場合、インタープリターはこれを_No such file
_エラーとして認識するためです。 :_Ruby myrubyscript --options arg1
_で、そのスクリプトのあるフォルダーにいない。
使用する $0
or $PROGRAM_NAME
現在実行中のファイル名を取得します。
これはあなたの質問に対する答えではありませんが、車輪を再発明しているようです。 optparse ライブラリを見てください。コマンドラインスイッチ、引数などを定義でき、すべての面倒な作業を行います。