Я пытаюсь выполнить чтение в строках из файла в C в среде оболочки - PullRequest
0 голосов
/ 05 февраля 2020

Я могу скомпилировать код, выполнить его с файлом в качестве аргумента командной строки, но ничего не происходит. Функция интерактивного режима запрашивает как обычно, но не функцию batchMode.

Я пытаюсь прочитать строку, а затем выполнить эту строку.

файл примера

date

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 = '\0';
    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);
      }

  }

}

Примечание. Это повторная попытка из предыдущего вопроса, который был заблокирован для неадекватной информации. Я обновил свой код и постарался быть максимально подробным. Я с радостью предоставлю что-нибудь еще, чтобы помочь ответить на мой вопрос.

Спасибо всем.

edit Я вставил fprintf, чтобы убедиться, что он читает файл и делает.

1 Ответ

0 голосов
/ 05 февраля 2020

Первое примечание во входном файле, последняя команда cd - это не системная команда, это встроенная оболочка, поэтому можно ожидать, что она завершится ошибкой (если не обработана специально).

Выделение для каждого токена (tok[i]), как обсуждалось с strdup (если доступно) или просто malloc (strlen(toks) + 1);, позволяет копировать текущий токен в выделенный блок памяти. Теперь каждый tok[i] будет ссылаться на отдельный сохраненный токен (вместо того, чтобы указывать на последний токен - поскольку всем назначен один и тот же указатель)

Самая большая ошибка logi c в batchMode как ваша вызов execvp с execvp (tok[i], tok); вместо правильного предоставления файла для выполнения как tok[0]. Будьте внимательны, если файл для выполнения находится не в вашем PATH, вы должны указать абсолютный путь во входном файле.

При внесении изменений ваш batchMode можно записать следующим образом (и удалить все неиспользуемые переменные и перемещение char *tok[100]; в пределах while l oop, поэтому оно объявляется в этой области):

#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

Пример использования / Вывод

$ ./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

Посмотрите вещи и дайте мне знать, если у вас есть вопросы:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...