ця відповідь може прийти трохи пізно, але у мене була та сама проблема, і прийнята відповідь здалася мені не зовсім задовольняючою, тому я дослідив трохи далі.
Мене турбував той факт, що $0
чи $PROGRAM_NAME
насправді не містив правильної інформації про те, що ввів користувач . Якщо мій сценарій Ruby знаходився в папці PATH і користувач ввів ім'я виконуваного файлу (без будь-яких визначень шляхів, таких як ./script
або/bin/script
), він завжди розширювався б до загального шляху.
Я думав, що це дефіцит Ruby, тому я спробував те саме з Python, і там, на мій жаль, нічим не відрізнявся.
Друг запропонував мені хак шукати real thing
in /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
і ви не в папці з цим сценарієм .