Given:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Usage: %s [OPTIONS]\n", argv[0]);
return 0;
}
Running it as `./dir/demo --help` gives: Usage: ./dir/demo [OPTIONS]
Put it somewhere in $PATH, and run it as `demo --help`, and it will give: Usage: demo [OPTIONS]
Perfect!But with a Bash script, argv[0] is erased, it sets $0 is set to script path passed to `bash` as an argument.
Given:
#!/bin/bash
echo "Usage: $0 [OPTIONS]"
Running it as `./dir/demo --help` gives: Usage: ./dir/demo [OPTIONS]
So good, so far, since the kernel ran "/bin/bash ./dir/demo --help". But once we get $PATH involved, $0 stops being useful, since the path passed to Bash is the resolved file path; if you put it in /usr/bin, and run it as `demo --help`, it will give: Usage: /usr/bin/demo [OPTIONS]
Because the call to execvpe() looks at $PATH, resolves "demo" to "/usr/bin/demo", then passes "/usr/bin/demo" to the execve() syscall, and the kernel runs "/bin/bash /usr/bin/demo --help".In POSIX shell, $0 is a little useful for looking up the source file, but isn't so useful for knowing how the user invoked you. In Bash, if you need the source file, you're better served by ${BASH_SOURCE[0]}, rendering $0 relatively useless. And neither has a way to know how the user invoked you... until now.
It's a small problem, but one that there was no solution for.