ця відповідь може прийти трохи пізно, але у мене була та сама проблема, і прийнята відповідь здалася мені не зовсім задовольняючою, тому я дослідив трохи далі.
Мене турбував той факт, що $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:
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);
}
Результат: `Використання: / home / danyel / bin / myscript FILE ...
Щоб довести, що це справді execveріч, а не з bash, ми можемо створити фіктивний інтерпретатор, який не робить нічого, крім друку аргументів, переданих йому:
// interpreter.c
int main(int argc, const char ** argv) {
while(*argv)
printf("%s\n", *(argv++));
}
Ми компілюємо його і поміщаємо в папку шляху (або ставимо повний шлях після shebang) і створюємо фіктивний сценарій в ~/bin/myscript/
Hi there!
Тепер у нашому 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);
}
Компіляція та запуск ./main: interpreter / home / danyel / bin / myscript -v /var/log/apache2.log
Причиною цього, швидше за все, є те, що якщо сценарій знаходиться у вашому PATH і не вказано повний шлях , інтерпретатор визнає це як No such fileпомилку, що і робиться, якщо ви це робите: ruby myrubyscript --options arg1і ви не в папці з цим сценарієм .