我正在尝试在 shell 环境中从 C 中的文件中读取行

I'm trying to execute read in lines from file in C in a shell environment

我可以编译代码,将文件作为命令行参数执行它,但没有任何反应。交互模式功能提示正常,batchMode功能提示不正常

我正在尝试读取一行,然后执行该行。

示例文件

日期

ls -la

CD

(行与行之间没有间距。我无法在此处正确设置格式。)

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>


#define bSize 1000


void driveLoop();
char *userInput(void);
void removeExit(char *original, char *subString); // removes string with substring "exit"
void batchMode(char *c);


int main(int argc, char **argv){

  char *fTemp;
  if (argc == 1)
    driveLoop(); // calls the loop function that accepts input and executes commands.

  else if (argc == 2)
    batchMode(&argv[1][0]);

  return 0;

}


void driveLoop(void){
  char *comTokens[100];
  char *tempTokens;
  char *command;
  char *cd;
  char *cdDir;
  char* cdTemp;
  char cdBuf[bSize];
  char checkExit[] = "exit";

  for (;;){


    printf("> ");
    command = userInput(); // reads input


    if (!*command) // allows for empty string error
      break;


    char *exitPtr = strstr(command, "exit"); // returns a value to a pointer if substring is found
    removeExit(command, "exit"); 
    puts(command); // updates the array after the function filter

    int i = 0;
    tempTokens = strtok(command, " \t\n"); // tokens are how the computer recognizes shell commands


    while (tempTokens && i < 99){ // geeksforgeeks.com
      comTokens[i++] = tempTokens;
      tempTokens = strtok(NULL, "\t\n");
    }


    if (strcmp(comTokens[0], "exit") == 0) // exit if input is "exit" only
      exit(0); 




    if(strcmp(comTokens[0], "cd") == 0){ // built in change directory command
      cd = getcwd(cdBuf, sizeof(cdBuf));
      cdDir = strcat(cd, "/");
      cdTemp = strcat(cdDir, comTokens[1]); // cplusplus.com reference
      chdir(cdTemp);
      continue;
    }

    comTokens[i] = NULL;


    pid_t cFork = fork(); // creates duplicate child process of parent


    if (cFork == (pid_t) - 1){ // error check
      perror("fork");
    }


    else if (cFork == 0) { // error codes found on cplusplus.com
      execvp(comTokens[0], comTokens);
      perror("exec");      
    }

    else { // children are returned. parent executes
      int status;
      waitpid(cFork, &status, 0);
      if (exitPtr != NULL){ // if substring exit was found, exit the program
    exit(0);
      }
    }


  }

}


char *userInput(void){  // referenced Linux man page - getline(3) (linux.die.net)
  char *input = NULL;
  size_t size = 0;
  getline(&input, &size, stdin); // updates the size as it goes along
  return input;
}


void removeExit(char *original, char *subString){ // removes exit from string
  char *ex;
  int len = strlen(subString); 
  while ((ex = strstr(original, subString))){ // Referenced from a Stack Overflow page.
    *ex = '[=11=]';
    strcat(original, ex+len);
  }
}


void batchMode(char *c){


  char *tok[100];
  char *batchTokens;
  char *batchBuffer = NULL;
  size_t batchSize = 0;


  FILE *fp = fopen(c, "r");


  unsigned int line = 1;
  char buffer[bSize];


  while(fgets(buffer, sizeof(buffer), fp)){

      int i = 0;


      char *toks = strtok(buffer, "\t\n");


      while (toks && i < 99){
           tok[i] = malloc (strlen(toks) + 1);
           strcpy(tok[i++], toks);
           toks = strtok(NULL, " \t\n");
      }


      tok[i] = NULL;
          pid_t bFork = fork();


      if (bFork == (pid_t) - 1)
          perror("fork");


      else if (bFork == 0){
         execvp(tok[i], tok);
         perror("exec");
      }


      else {
        int status;
        waitpid(bFork, &status, 0);
      }

  }

}

旁注。这是对先前因信息不足而被锁定的问题的重新尝试。我已经更新了我的代码并尝试尽可能详细。 我很乐意提供进一步的信息来帮助回答我的问题。

谢谢大家

编辑 我放入了一个 fprintf 来验证它是否读取了文件,它确实读取了文件。

首先注意你的输入文件,最后一个命令 cd 不是系统命令,它是一个 shell 内置命令,所以你会认为它会失败(除非特别处理).

为每个令牌 (tok[i]) 分配 strdup(如果可用)或简单地 malloc (strlen(toks) + 1); 允许您将当前令牌复制到分配的内存块。现在每个 tok[i] 将引用保存的单个标记(而不是全部指向最后一个标记——因为所有标记都被分配了相同的指针)

batchMode 中最大的逻辑错误是您使用 execvp (tok[i], tok); 调用 execvp,而不是正确提供要作为 tok[0] 执行的文件。请注意,如果要执行的文件不在您的 PATH 中,您必须在输入文件中提供绝对路径。

进行更改,您的 batchMode 可以如下编写(并删除所有未使用的变量并在 while 循环内移动 char *tok[100]; 以便在该范围内声明它) :

#include <sys/types.h>
#include <sys/wait.h>
...
void batchMode(char *c)
{
    char buffer[bSize];
    FILE *fp = fopen (c, "r");

    if (!fp) {
        perror ("fopen-c");
        return;
    }

    while (fgets (buffer, sizeof(buffer), fp)) {

        int i = 0;
        char *tok[100];
        char *toks = strtok(buffer, " \t\n");

        while (toks && i < 99){
            tok[i] = malloc (strlen(toks) + 1);
            strcpy(tok[i++], toks);
            toks = strtok(NULL, " \t\n");
        }

        tok[i] = NULL;
            pid_t bFork = fork();

        if (bFork == (pid_t) - 1)
            perror("fork");
        else if (bFork == 0){
            execvp (tok[0], tok);
            perror("exec");
        }
        else {
            int status;
            waitpid(bFork, &status, 0);
        }
    }
}

示例输入文件

我测试了两个简单的输入文件:

$ cat dat/toksfile.txt
echo hello
echo goodbye

$ cat dat/toksfile2.txt
date
ls -al dat/toksfile.txt
cd

例子Use/Output

$ ./bin/shellorbatch dat/toksfile.txt
hello
goodbye

$ ./bin/shellorbatch dat/toksfile2.txt
Tue Feb  4 23:47:00 CST 2020
-rw-r--r-- 1 david david 24 Feb  4 23:24 dat/toksfile.txt
exec: No such file or directory

检查一下,如果您有任何问题,请告诉我: