代码之家  ›  专栏  ›  技术社区  ›  Gergely

如何用shebang定义脚本解释器

  •  7
  • Gergely  · 技术社区  · 12 年前

    很明显,可以使用

    #!/usr/bin/perl
    

    在脚本的第一行使用shebang表示法来定义解释器。然而,这需要一个解释器来忽略作为注释的hashmark起始行。如何使用没有此功能的解释器?

    3 回复  |  直到 12 年前
        1
  •  4
  •   holgero    12 年前

    使用一个包装器,该包装器删除第一行并使用文件的剩余部分调用真正的解释器。它可能看起来是这样的:

    #!/bin/sh
    
    # set your "real" interpreter here, or use cat for debugging
    REALINTERP="cat"
    
    tail -n +2 $1 | $REALINTERP
    

    除此之外:在某些情况下,忽略关于第一行的错误消息可能是一种选择。

    最后的办法是:将解释器的注释字符代码支持到内核中。

        2
  •  3
  •   Fritz G. Mehner    12 年前

    我认为第一行是由操作系统解释的。 将启动解释器,并将脚本的名称作为其第一个参数传递给脚本。 以下脚本“first.mint”调用解释器“myinterpreter”,该解释器是下面C程序的可执行文件。

    #!/usr/local/bin/myinterpreter
    % 1 #########
    2 xxxxxxxxxxx
    333
    444
    % the last comment
    

    个人口译员示意图:

    #include <errno.h>
    #include <stdio.h> 
    #include <stdlib.h>
    #include <string.h>
    
    #define BUFFERSIZE  256                         /* input buffer size */
    
      int
    main ( int argc, char *argv[] )
    {
      char    comment_leader  = '%';                /* define the coment leader */
      char    *line = NULL;
      size_t  len   = 0;
      ssize_t read;
      //  char  buffer[BUFFERSIZE];
    
      // argv[0] : the name of this executable
      // argv[1] : the name the script calling this executable via shebang
    
      FILE  *input;                                 /* input-file pointer */
      char  *input_file_name = argv[1];             /* the script name    */
    
      input = fopen( input_file_name, "r" );
      if ( input == NULL ) {
        fprintf ( stderr, "couldn't open file '%s'; %s\n",
            input_file_name, strerror(errno) );
        exit (EXIT_FAILURE);
      }
    
      while ((read = getline(&line, &len, input)) != -1) {
        if ( line[0] != comment_leader ) {
          printf( "%s", line );                     /* print line as a test */
        }
        else {
          printf ( "Skipped a comment!\n" );
        }
      }
    
      free(line);
    
      if( fclose(input) == EOF ) {                  /* close input file   */
        fprintf ( stderr, "couldn't close file '%s'; %s\n",
            input_file_name, strerror(errno) );
        exit (EXIT_FAILURE);
      }
    
      return EXIT_SUCCESS;
    }   /* ----------  end of function main  ---------- */
    

    现在调用脚本(之前已使其可执行)并查看输出:

    ...~> ./first.myint
    #!/usr/local/bin/myinterpreter
    Skipped a comment!
    2 xxxxxxxxxxx
    333
    444
    Skipped a comment!
    
        3
  •  1
  •   Community Mohan Dere    8 年前

    我成功了。我特别感谢霍尔杰罗的翘尾技巧

    tail -n +2 $1 | $REALINTERP
    

    这一点,以及在堆栈溢出上找到这个答案,使得它成为可能:

    How to compile a linux shell script to be a standalone executable *binary* (i.e. not just e.g. chmod 755)?

    “完全满足我需求的解决方案是SHC——一个免费的工具”

    SHC是一个shell到C的转换器,请参阅此处:

    http://www.datsi.fi.upm.es/~frosal/

    所以我写了 polyscript.sh :

    $ cat polyscript.sh
    #!/bin/bash
    
    tail -n +2 $1 | poly
    

    我用shc和gcc编译了这个:

    $ shc-3.8.9/shc -f polyscript.sh
    $ gcc -Wall polyscript.sh.x.c -o polyscript
    

    现在,我能够创建第一个用ML编写的脚本:

    $ cat smlscript
    #!/home/gergoe/projects/shebang/polyscript $0
    
    print "Hello World!"
    

    而且,我能够运行它:

    $ chmod u+x smlscript
    $ ./smlscript
    Poly/ML 5.4.1 Release
    > > # Hello World!val it = (): unit
    

    Poly没有抑制编译器输出的选项,但这不是问题。按照fgm的建议,直接用C编写polyscript可能很有趣,但这可能不会让它更快。

    所以,事情就是这么简单。我欢迎任何评论。