ada*_*m_0 76 ruby command-line
我不久前写了一篇不错的小Ruby脚本,我非常喜欢.我想通过检查适当数量的参数来提高其稳健性:
if ARGV.length != 2 then
puts "Usage: <command> arg1 arg2"
end
Run Code Online (Sandbox Code Playgroud)
当然那是伪代码.不管怎么说,在C或C++我可以用argv[0]得到的名称,用户用得到我的指挥,无论他们把它叫做喜欢./myScript.rb或myScript.rb或/usr/local/bin/myScript.rb.在Ruby中,我知道这ARGV[0]是第一个真正的参数,并且ARGV不包含命令名称.有什么方法可以得到这个吗?
the*_*Man 141
Ruby有三种方法可以为我们提供被调用脚本的名称:
#!/usr/bin/env ruby
puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"
Run Code Online (Sandbox Code Playgroud)
将该代码保存为"test.rb"并调用它几个方式表明该脚本接收到操作系统传递给它的名称.脚本只知道操作系统告诉它的内容:
$ ./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
Run Code Online (Sandbox Code Playgroud)
~在第二个示例中使用$ HOME 的快捷方式调用它会显示操作系统将其替换为扩展路径,与第三个示例中的内容相匹配.在所有情况下,它都是操作系统传入的内容.
使用硬链接和软链接链接到文件会显示一致的行为.我为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
Run Code Online (Sandbox Code Playgroud)
ruby test.rb使用脚本名称的任何变体启动都会返回一致的结果.
如果您只需要被调用的文件名,则可以将File的basename方法与其中一个变量一起使用,或者在分隔符上拆分并获取最后一个元素.
$0并且__FILE__有一些细微的差别,但对于单个脚本,它们是等效的.
puts File.basename($0)
Run Code Online (Sandbox Code Playgroud)
次要补充:
有使用一些好处File.basename,File.extname和File.dirname方法的套件.basename采用一个可选参数,这是strip的扩展,所以如果你只需要没有扩展名的basename
File.basename($0, File.extname($0))
Run Code Online (Sandbox Code Playgroud)
没有重新发明轮子或不得不处理可变长度或缺少扩展或不正确地截断扩展链的可能性" .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"
Run Code Online (Sandbox Code Playgroud)
Dan*_*yel 16
这个答案可能会有点晚,但我遇到了同样的问题,而且接受的答案对我来说似乎并不令人满意,所以我进一步调查了一下.
困扰我的是这样一个事实:$0或者$PROGRAM_NAME没有真正掌握用户输入内容的正确信息.如果我的Ruby脚本位于PATH文件夹中并且用户输入了可执行文件名(没有任何路径定义,例如./script或/bin/script),它将始终扩展到总路径.
我认为这是一个Ruby缺陷,所以我用Python尝试了同样的东西,让我感到懊恼的是,它没有什么不同.
一位朋友建议我查找real thingin /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);
}
Run Code Online (Sandbox Code Playgroud)
输出:`用法:/ home/danyel/bin/myscript文件...
为了证明这确实是一个execve事情,而不是来自bash,我们可以创建一个虚拟解释器,除了打印传递给它的参数之外什么都不做:
// interpreter.c
int main(int argc, const char ** argv) {
while(*argv)
printf("%s\n", *(argv++));
}
Run Code Online (Sandbox Code Playgroud)
我们编译它并将其放在路径文件夹中(或者放在shebang之后的完整路径)并在其中创建一个虚拟脚本 ~/bin/myscript/
#!/usr/bin/env interpreter
Hi there!
Run Code Online (Sandbox Code Playgroud)
现在,在我们的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);
}
Run Code Online (Sandbox Code Playgroud)
编译和运行./main:interpreter/home/danyel/bin/myscript -v /var/log/apache2.log
最有可能的原因是,如果脚本在您的PATH中并且未提供完整路径,则解释器会将此识别为No such file错误,如果您这样做,它会执行以下操作:ruby myrubyscript --options arg1并且您不在该脚本的文件夹中.
| 归档时间: |
|
| 查看次数: |
29753 次 |
| 最近记录: |