解释器如何检测从脚本而不是命令行调用?

时间:2017-11-16 21:57:32

标签: arguments shebang

作为"is known",以

开头的脚本my-script-file
#!/path/to/interpreter -arg1 val1 -arg2 val2

exec使用 2 (!)参数调用/path/to/interpreter执行:

  1. -arg1 val1 -arg2 val2
  2. my-script-file
  3. (和不是,正如人们可能天真地期待的那样,有5个参数

    1. -arg1
    2. val1
    3. -arg2
    4. val2
    5. my-script-file
    6. 正如之前许多问题中所解释的那样,例如, https://stackoverflow.com/a/4304187/850781)。

      我的问题来自解释程序开发人员的POV,不是脚本编写者

      如何检测从{bbang调用的interpreter可执行文件内部而不是命令行?

      然后我将能够决定是否需要拆分我的第一个参数 按空格从"-arg1 val1 -arg2 val2"转到["-arg1", "val1", "-arg2", "val2"]或不。{/ p>

      这里的主要问题是以空格命名的脚本文件。 如果我总是分开第一个论点,我会这样失败:

      $ my-interpreter "weird file name with spaces"
      my-interpreter: "weird": No such file or directory
      

1 个答案:

答案 0 :(得分:2)

在Linux上,使用GNU libc或musl libc,您可以使用aux-vector区分这两种情况。

以下是一些示例代码:

#define _GNU_SOURCE 1
#include <stdio.h>
#include <errno.h>
#include <sys/auxv.h>
#include <sys/stat.h>

int
main (int argc, char* argv[])
{
  printf ("argv[0] = %s\n", argv[0]);
  /* https://www.gnu.org/software/libc/manual/html_node/Error-Messages.html */
  printf ("program_invocation_name = %s\n", program_invocation_name);
  /* http://man7.org/linux/man-pages/man3/getauxval.3.html */
  printf ("auxv[AT_EXECFN] = %s\n", (const char *) getauxval (AT_EXECFN));
  /* Determine whether the last two are the same. */
  struct stat statbuf1, statbuf2;
  if (stat (program_invocation_name, &statbuf1) >= 0
      && stat ((const char *) getauxval (AT_EXECFN), &statbuf2) >= 0)
    printf ("same? %d\n", statbuf1.st_dev == statbuf2.st_dev && statbuf1.st_ino == statbuf2.st_ino);
}

直接调用的结果:

$ ./a.out 
argv[0] = ./a.out
program_invocation_name = ./a.out
auxv[AT_EXECFN] = ./a.out
same? 1

通过以#!/home/bruno/a.out开头的脚本调用的结果:

$ ./a.script 
argv[0] = /home/bruno/a.out
program_invocation_name = /home/bruno/a.out
auxv[AT_EXECFN] = ./a.script
same? 0

这种方法当然非常不可移植:只有Linux具有getauxv功能。并且肯定会出现效果不佳的情况。