Ruby에서 사용 프롬프트를 위해 호출되는 명령의 이름을 어떻게 얻을 수 있습니까?
얼마 전에 내가 좋아하는 멋진 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에는 호출 된 스크립트의 이름을 제공하는 세 가지 방법이 있습니다.
#!/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
~
두 번째 예에서 $ HOME 의 바로 가기를 사용하여 호출 하면 OS가 세 번째 예와 일치하는 확장 된 경로로 대체되는 것을 보여줍니다. 모든 경우에 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
스크립트 이름의 변형을 사용하여 시작 하면 일관된 결과가 반환됩니다.
호출 된 파일 이름 만 원하는 경우 basename
변수 중 하나와 함께 File의 메서드를 사용 하거나 구분 기호에서 분할하고 마지막 요소를 사용할 수 있습니다.
$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"
이 답변은 조금 늦을 수도 있지만 같은 문제가 있었고 받아 들여진 답변이 나에게 그다지 만족스럽지 않아서 조금 더 조사했습니다.
What bothered me was the fact that $0
or $PROGRAM_NAME
did not really hold the correct information about what the user had typed. If my Ruby script was in a PATH folder and the user entered the executable name (without any path definitions such as ./script
or /bin/script
), it would always expand to the total path.
I thought this was a Ruby deficite, so I tried the same with Python and to my chagrin there, it was no different.
A friend suggested me a hack to look for the real thing
in /proc/self/cmdline
, and the result was: [ruby, /home/danyel/bin/myscript, arg1, arg2...]
(separated by the null-char). The villain here is execve(1)
which expands the path to the total path when it passes it to an interpreter.
Example C program:
#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);
}
Output: `Usage: /home/danyel/bin/myscript FILE...
To prove that this is indeed a execve
thing and not from bash, we can create a dummy interpreter that does nothing but print out the arguments passed to it:
// interpreter.c
int main(int argc, const char ** argv) {
while(*argv)
printf("%s\n", *(argv++));
}
We compile it and put it in a path folder (or put the full path after the shebang) and create a dummy script in ~/bin/myscript/
#!/usr/bin/env interpreter
Hi there!
Now, in our 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);
}
Compiling and running ./main
: interpreter /home/danyel/bin/myscript -v /var/log/apache2.log
The reason behind this most likely is that if the script is in your PATH and the full path were not provided, the interpreter would recognize this as a No such file
error, which it does if you do: ruby myrubyscript --options arg1
and you're not in the folder with that script.
Use $0
or $PROGRAM_NAME
to get the file name that is currently being executed.
This isn't quite an answer to your question, but it sounds like you're reinventing a wheel. Look at the optparse library. It lets you define command line switches, arguments, etc, and it'll do all the heavy lifting for you.
'development' 카테고리의 다른 글
"같지 않음"CSS 속성 선택기를 찾을 수 없습니다. (0) | 2020.10.16 |
---|---|
TypeError : console.log (…)는 함수가 아닙니다. (0) | 2020.10.16 |
org.w3c.dom.Document 객체를 문자열로 어떻게 변환합니까? (0) | 2020.10.16 |
숫자 인 ID로 querySelector 사용 (0) | 2020.10.16 |
이 typedef 문은 무엇을 의미합니까? (0) | 2020.10.16 |