Ruby tem três maneiras de nos fornecer o nome do script chamado:
puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"
Salvar esse código como "test.rb" e chamá-lo de algumas maneiras mostra que o script recebe o nome conforme foi transmitido a ele pelo sistema operacional. Um script sabe apenas o que o sistema operacional diz:
$ ./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
Chamá-lo usando o ~
atalho para $ HOME no segundo exemplo mostra o SO substituindo-o pelo caminho expandido, correspondendo ao que está no terceiro exemplo. Em todos os casos, é o que o sistema operacional passou.
Vincular ao arquivo usando links físicos e virtuais mostra um comportamento consistente. Criei um link físico para test1.rb e um link simbólico para 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
Iniciar ruby test.rb
com qualquer uma das variações no nome do script retorna resultados consistentes.
Se você quiser apenas o nome do arquivo chamado, você pode usar o basename
método de File com uma das variáveis ou dividir no delimitador e pegar o último elemento.
$0
e __FILE__
têm algumas pequenas diferenças, mas para scripts únicos são equivalentes.
puts File.basename($0)
Existem algumas vantagens de se utilizar o File.basename
, File.extname
e File.dirname
conjunto de métodos. basename
recebe um parâmetro opcional, que é a extensão para strip, então se você precisar apenas do nome de base sem a extensão
File.basename($0, File.extname($0))
faz isso sem reinventar a roda ou ter que lidar com extensões de comprimento variável ou ausentes ou a possibilidade de truncar incorretamente cadeias de extensão " .rb.txt
" por exemplo:
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"
esta resposta pode vir um pouco tarde, mas eu tive o mesmo problema e a resposta aceita não me pareceu muito satisfatória, então investiguei um pouco mais.
O que me incomodou foi o fato de que
$0
ou$PROGRAM_NAME
realmente não armazenar as informações corretas sobre o que o usuário tinha digitado . Se meu script Ruby estivesse em uma pasta PATH e o usuário inserisse o nome do executável (sem nenhuma definição de caminho como./script
ou/bin/script
), ele sempre se expandiria para o caminho total.Achei que era uma deficiência de Ruby, então tentei o mesmo com Python e, para minha tristeza, não foi diferente.
Um amigo me sugeriu um hack para procurar o
real thing
in/proc/self/cmdline
, e o resultado foi:[ruby, /home/danyel/bin/myscript, arg1, arg2...]
(separado por null-char). O vilão aqui éexecve(1)
quem expande o caminho até o caminho total quando passa para um intérprete.Exemplo de programa 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); }
Saída: ʻUsage: / home / danyel / bin / myscript FILE ...
Para provar que isso é realmente uma
execve
coisa e não do bash, podemos criar um interpretador fictício que não faz nada além de imprimir os argumentos passados para ele:// interpreter.c int main(int argc, const char ** argv) { while(*argv) printf("%s\n", *(argv++)); }
Nós compilamos e colocamos em uma pasta de caminho (ou colocamos o caminho completo após o shebang) e criamos um script fictício em
~/bin/myscript/
#!/usr/bin/env interpreter Hi there!
Agora, em nosso 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); }
Compilando e executando
./main
: interpreter / home / danyel / bin / myscript -v /var/log/apache2.logA razão por trás disso provavelmente é que se o script estiver em seu PATH e o caminho completo não for fornecido, o intérprete reconhecerá isso como um
No such file
erro, o que acontecerá se você fizer isso:ruby myrubyscript --options arg1
e você não estiver na pasta com esse script .fonte
Use
$0
ou$PROGRAM_NAME
para obter o nome do arquivo que está sendo executado.fonte
/usr/local/bin/myScript
e/usr/local/bin
está no meu$PATH
e apenas digitomyScript
, recebo/usr/local/bin/myScript
de$0
$0.split("/").last
?./myScript
, quero uma variável que me forneça./myScript
. Se eles digitaram/usr/bin/local/myScript
, eu quero exatamente isso. etc.Esta não é exatamente uma resposta à sua pergunta, mas parece que você está reinventando uma roda. Veja a biblioteca optparse . Ele permite que você defina opções de linha de comando, argumentos, etc, e fará todo o trabalho pesado para você.
fonte