我正在尝试在 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
检查一下,如果您有任何问题,请告诉我:
我可以编译代码,将文件作为命令行参数执行它,但没有任何反应。交互模式功能提示正常,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
检查一下,如果您有任何问题,请告诉我: