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:
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/
Hi there!
Agora, em nosso main.c:
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.log
A 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 .