2016-06-11 43 views
0

我正在寫一個定製的外殼,我希望它執行一個腳本:shebang for custom shell?

if [ type less > /dev/null ];then PAGER=less; fi 
echo $PAGER 
printenv|grep $1|$PAGER 

如果我從bash和我的定製外殼運行它的工作原理:

$ ./shell -f ../checkenv.sh GNOME 
[13607] 
[13606] 
GNOME_KEYRING_CONTROL= 
GNOME_KEYRING_PID= 
GNOME_DESKTOP_SESSION_ID=this-is-deprecated 
INSTANCE=GNOME 
XDG_CURRENT_DESKTOP=GNOME 
(END) 

但是,如果我啓動我的shell,然後嘗試運行該腳本,我收到一條錯誤消息。

$ ./shell 
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin. 
$ ../checkenv.sh GNOME 
14786: executing ../checkenv.sh 
../checkenv.sh: 2: [: type: unexpected operator 

14786: executed 
$ 

這似乎是因爲我沒有shebang,但我不知道如何使用shebang作爲自定義shell。我應該在/usr/bin/中安裝我的自定義外殼還是進行其他安排?

我的主要功能和我readline的功能有:

int main(int argc, char *argv[]) { 
    bool donotrun = false; 
    struct sigaction new_action, old_action; 
    hashtable_t *hashtable = ht_create(65536); 
    /* Set up the structure to specify the new action. */ 
    new_action.sa_handler = termination_handler; 
    sigemptyset(&new_action.sa_mask); 
    new_action.sa_flags = 0; 

    sigaction(SIGINT, NULL, &old_action); 
    if (old_action.sa_handler != SIG_IGN) 
     sigaction(SIGINT, &new_action, NULL); 
    sigaction(SIGHUP, NULL, &old_action); 
    if (old_action.sa_handler != SIG_IGN) 
     sigaction(SIGHUP, &new_action, NULL); 
    sigaction(SIGTERM, NULL, &old_action); 
    if (old_action.sa_handler != SIG_IGN) 
     sigaction(SIGTERM, &new_action, NULL); 

    bool background = false; 
    int index = 0; 
    int i; 
    char *cvalue = NULL; 
    const char *commandFile = NULL; 

    while (1) { 
     index = 0; 
     i = getopt_long(argc, argv, "pc:fvh", 
         options, &index); 
     if (i == -1) 
      break; 
     switch (i) { 
      case 'p': { 
       exit(EXIT_SUCCESS); 
      } 
      case 'v': { 
       printf("sh OpenShell version 0.1(a)\n"); 
       printf("Version: %s\n", VERSION); 

       // printf ("%s/%s/%s/%s\n", 
       //   program_name, version, 
        //  build_date, build_git_sha); 


       exit(EXIT_SUCCESS); 

      } 
      case 'h': { 
       usage(); 
       exit(EXIT_SUCCESS); 

      } 
      case 'c': { 
       cvalue = optarg; 
       command(cvalue, hashtable, background); 
       exit(EXIT_SUCCESS); 
      } 

      case 'f': { 
       /* 
       * Execute commands from file. 
       * This is used for osh script files. 
       * The quiet flag is also set. 
       */ 
       //if ((argc != 1) || commandFile) 
        //usage(); 
       //quietFlag = TRUE; 
       printf("case f\n"); 
       //commandFile = *argv++; 

       argc--; 
       *argv++; 
       *argv++; 
       readFile(*argv++, argc, argv, hashtable, background); 
       //free(line); 
       exit(0); 

       //break; 
      } 

      case '?': 
       if (optopt == 'c') 
        fprintf(stderr, "Option -%c requires an argument.\n", optopt); 
       else if (isprint (optopt)) 
        fprintf(stderr, "Unknown option `-%c'.\n", optopt); 
       else 
        fprintf(stderr, 
          "Unknown option character `\\x%x'.\n", 
          optopt); 
      default: { 
       return 1; 
      } 
     } 
    } 
    getPath(); 
    char *copy = ""; 

    for (; ;) { 
     bool scanning = true; 
     while (scanning) { 
      char *line = NULL; 
      line = readline("$ "); 
      if (line == NULL) { 
       /* No more lines, so exit the loop. */ 
       break; 
      } 
      if (line) 
       copy = strdup(line); 

      if (line && !strstr(line, "for") && !strstr(line, "==") && !strstr(line, "if") && strstr(line, "=")) { 
       donotrun = true; 
       char str[128]; 
       char *ptr; 
       strcpy(str, line); 
       strtok_r (str, "=", &ptr); 
       ht_set(hashtable, str, ptr); 
      } 

      if (!scanning) 
       break; 

      if (commandFile!=NULL || !isatty(fileno(stdin))) { 
       *argv++; 
       readFile(*argv++, argc, argv, hashtable, background); 
       free(line); 
       exit(0); 
      } 
      else { 
       if (!donotrun) { 
        line = strrep(line, " | ", "|"); 
        line = strrep(line, " |", "|"); 
        background = testFn2(line); 
        if (background) 
         line[strlen(line) - 1] = '\0'; 
        command(line, hashtable, background); 
       } 
       donotrun = false; 
       add_history(copy); 

      } 
      free(copy); 
     } 
    } 
    // ParseFree(pParser, free);FIXME: where should this go? 
    return 0; 
} 


/* 
* Read commands from the specified file. 
* A null name pointer indicates to read from stdin. 
*/ 
static int readFile(const char *name, int argc, char ** argv, hashtable_t *hashtable, bool background) { 
    FILE *fp; 
    int cc; 
    bool ttyFlag; 
    char buf[CMD_LEN]; 
    int r = 0; 

    if (sourceCount >= MAX_SOURCE) { 
     fprintf(stderr, "Too many source files\n"); 

     return 1; 
    } 

    fp = stdin; 
    printf("name %s\n", name); 

    if (name) { 
     fp = fopen(name, "r"); 

     if (fp == NULL) { 
      perror(name); 

      return 1; 
     } 
    } 

    sourcefiles[sourceCount++] = fp; 

    ttyFlag = isatty(fileno(fp)); 
    int i = 0; 
    while (true) { 
     if (ttyFlag) 
      showPrompt(); 

     if (intFlag && !ttyFlag && (fp != stdin)) { 
      fclose(fp); 
      sourceCount--; 

      return 1; 
     } 
     if (fgets(buf, CMD_LEN - 1, fp) == NULL) { 
      if (ferror(fp) && (errno == EINTR)) { 
       clearerr(fp); 

       continue; 
      } 

      break; 
     } 

     cc = strlen(buf); 
     if (buf[cc - 1] == '\n') 
      cc--; 

     while ((cc > 0) && isBlank(buf[cc - 1])) 
      cc--; 

     buf[cc] = '\0'; 
     //printf("buf %s\n", argv[0]); 
     strreplace(buf, "$1", argv[0]); 

     //printf("arg %s\n", ++argv); 

     if (strstr(buf, "=")) { 
      char str[128]; 
      char *ptr; 
      strcpy(str, buf); 
      strtok_r (str, "=", &ptr); 
      ht_set(hashtable, str, ptr); 
     } 

     //printf("the command is %s\n", buf); 
     r = command(buf, hashtable, background); 
     i++; 
    } 

    if (ferror(fp)) { 
     perror("Reading command line"); 

     if (fp == stdin) 
      exit(1); 
    } 

    clearerr(fp); 

    if (fp != stdin) 
     fclose(fp); 

    sourceCount--; 

    return r; 
} 
+1

目前還不清楚這是如何與C或您的shell的源代碼相關。 She-bang是執行環境的一個特性,並且與C無關。 – Olaf

+3

爲什麼不試試'#!/ path/to/my/shell'並查看會發生什麼? – a3f

+0

順便說一句,'[]'不是'if'語法的一部分。這與分組運營商的對手或花括號不同。從字面上看,'['是'test'命令的別名; '如果[2-gt 1]'在任何方面**都是**,相當於'if test 2 -gt 1'(每個我讀過的源代碼的shell都使用相同的函數實現它們)你會發現你的操作系統提供了一個'/ usr/bin/['就像它做了一個'/ usr/bin/test'一樣(儘管現代shell會有一個內建版本,而且啓動速度更快,因此上面描述的內置版本)。 –

回答

1

你可能只是去掉方括號在你的腳本測試:

if type less > /dev/null ;then PAGER=less; fi 
echo $PAGER 
printenv|grep $1|$PAGER 
2

一個家當行只指定了解釋器的完整路徑,加上(可選)要傳遞的參數。

顯然,您的自定義shell需要-f後跟腳本名稱,後面跟隨任何要傳遞給腳本的參數。

所以纔將其添加爲腳本的第一行:

#!/path/to/shell -f 

,並確保該腳本有執行權限。您的外殼不必安裝在/usr/bin;您只需在#!行上指定完整路徑。

還有一個/usr/bin/env黑客:

#!/usr/bin/env shell 

,但在許多系統上它不允許傳遞一個額外的參數。 (您可能考慮修改您的自定義外殼程序,因此它將腳本名稱作爲參數而沒有-f。)我已在this answer中討論了#!/usr/bin/env的優缺點。

請注意,#!機制由內核處理,而不是由shell處理。