Ruby tiene tres formas de darnos el nombre del script llamado:
puts "$0 : #{$0}"
puts "__FILE__ : #{__FILE__}"
puts "$PROGRAM_NAME : #{$PROGRAM_NAME}"
Guardar ese código como "test.rb" y llamarlo de dos maneras muestra que el script recibe el nombre tal como se lo pasó por el sistema operativo. Un script solo sabe lo que le dice el sistema operativo:
$ ./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
Llamarlo usando el ~
acceso directo para $ HOME en el segundo ejemplo muestra que el sistema operativo lo reemplaza con la ruta expandida, que coincide con lo que está en el tercer ejemplo. En todos los casos es lo que pasó el sistema operativo.
La vinculación al archivo mediante enlaces físicos y blandos muestra un comportamiento coherente. Creé un enlace duro para test1.rb y un enlace suave 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
El lanzamiento ruby test.rb
con cualquiera de las variaciones del nombre del script arroja resultados consistentes.
Si solo desea el nombre de archivo llamado, puede usar el basename
método de File con una de las variables o dividir en el delimitador y tomar el último elemento.
$0
y __FILE__
tienen algunas diferencias menores, pero para scripts únicos son equivalentes.
puts File.basename($0)
Hay algunas ventajas a usar el File.basename
, File.extname
y File.dirname
conjunto de métodos. basename
toma un parámetro opcional, que es la extensión para eliminar, por lo que si solo necesita el nombre de base sin la extensión
File.basename($0, File.extname($0))
lo hace sin reinventar la rueda o tener que lidiar con extensiones de longitud variable o faltantes o la posibilidad de truncar incorrectamente cadenas de extensión " .rb.txt
" por ejemplo:
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 respuesta puede llegar un poco tarde, pero he tenido el mismo problema y la respuesta aceptada no me pareció muy satisfactoria, así que investigué un poco más.
Lo que me molestó fue el hecho de que
$0
, o$PROGRAM_NAME
en realidad no tiene la información correcta sobre lo que el usuario hubiera tecleado . Si mi script Ruby estaba en una carpeta PATH y el usuario ingresó el nombre del ejecutable (sin ninguna definición de ruta como./script
o/bin/script
), siempre se expandiría a la ruta total.Pensé que esto era un déficit de Ruby, así que intenté lo mismo con Python y, para mi disgusto, no fue diferente.
Un amigo me sugirió un truco para buscar la
real thing
en/proc/self/cmdline
, y el resultado fue:[ruby, /home/danyel/bin/myscript, arg1, arg2...]
(separados por la nula-char). El villano aquí es elexecve(1)
que expande el camino al camino total cuando se lo pasa a un intérprete.Programa de ejemplo 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); }
Salida: `Uso: / home / danyel / bin / myscript ARCHIVO ...
Para demostrar que esto es realmente una
execve
cosa y no de bash, podemos crear un intérprete ficticio que no hace más que imprimir los argumentos que se le pasan:// interpreter.c int main(int argc, const char ** argv) { while(*argv) printf("%s\n", *(argv++)); }
Lo compilamos y lo colocamos en una carpeta de ruta (o colocamos la ruta completa después del shebang) y creamos un script ficticio en
~/bin/myscript/
#!/usr/bin/env interpreter Hi there!
Ahora, en nuestro 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 y ejecutando
./main
: interpreter / home / danyel / bin / myscript -v /var/log/apache2.logLo más probable es que la razón detrás de esto sea que si el script está en su PATH y no se proporcionó la ruta completa , el intérprete reconocería esto como un
No such file
error, lo que hace si lo hace:ruby myrubyscript --options arg1
y no está en la carpeta con ese script .fuente
Utilice
$0
o$PROGRAM_NAME
para obtener el nombre del archivo que se está ejecutando actualmente.fuente
/usr/local/bin/myScript
y/usr/local/bin
está en mi$PATH
, y solomyScript
/usr/local/bin/myScript
$0
$0.split("/").last
?./myScript
, quiero una variable que me dé./myScript
. Si escribieron/usr/bin/local/myScript
, quiero exactamente eso. etc.Esta no es una respuesta a tu pregunta, pero parece que estás reinventando una rueda. Mire la biblioteca optparse . Le permite definir interruptores de línea de comando, argumentos, etc., y hará todo el trabajo pesado por usted.
fuente