gpt4 book ai didi

c - 用 C 为操作系统编写 shell 模拟器 : Shell not staying active after multiple commands given

转载 作者:太空宇宙 更新时间:2023-11-04 06:54:41 25 4
gpt4 key购买 nike

<分区>

这些是要求:

  1. 可以执行带参数的命令。
  2. 识别多个管道请求并处理它们。
  3. 识别重定向请求并处理它们。
  4. 键入“exit”退出 shhh shell。

这是我的问题:

每当我执行多个命令(使用 command1 | command2)时,我的 shell 在执行给定的命令后终止,而不是在我的 shell 中等待另一个命令行提示符。该程序应该继续运行,并允许用户输入更多命令,直到输入“退出”。

Code: 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
// professor-supplied variables for commands and command parsing
char *path, *argv[20], buf[80], n, *p;
int m, status, inword, continu;

// flags for redirection (note: C does not have type bool; using integer value 0 or 1)
int inputRedirectFlag, outputRedirectFlag, backgroundJobFlag;
int numArguments, argIndex, argCount, pipes, openPipesCount, pid, directoryIndex;

// pipes
int p1[2], p2[2];

// index for directory set prior to while(1)
directoryIndex = 0;

while (1) {


inword = 0;
p = buf;
m = 0;
continu = 0;
numArguments = 0;
argIndex = 0;
argCount = 0;
pipes = 0;
openPipesCount = 0;
pid = 0;

// required containers
int argumentContainer[20] = { 0 };
char currentDirectory[80] = { 0 };

// file variables
char *outputFile = (char *)0;
char *inputFile = (char *)0;

// redirection flags
inputRedirectFlag = 0;
outputRedirectFlag = 0;
backgroundJobFlag = 0;

// SHELL PROMPT
printf("\nshhh> ");

// COMMAND PARSING
while ((n = getchar()) != '\n' || continu)
{
/*************************************************
required addition to remediate segmentation fault
*************************************************/
if (n == EOF){
exit(0);
}

if (n == ' ') {
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
}

*p++ = 0;
argv[m] = 0;

// capture current working directory
getcwd(currentDirectory, 80);

// user wishes to terminate program
if (strcmp(argv[0], "exit") == 0)
exit(0);

// managing input and output redirection and piping
while (argv[argCount] != 0) {
if (strcmp(argv[argCount], "<") == 0)
{
inputFile = strdup(argv[argCount + 1]);
argv[argCount] = 0;
argv[argCount + 1] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[argCount], ">") == 0)
{
outputFile = strdup(argv[argCount + 1]);
argv[argCount] = 0;
argv[argCount + 1] = 0;
outputRedirectFlag = 1;
}
else if (strcmp(argv[argCount], "&") == 0)
{
argv[argCount] = 0;
backgroundJobFlag = 1;
}
else if (strcmp(argv[argCount], "|") == 0)
{
argv[argCount] = 0;
argumentContainer[pipes + 1] = argCount + 1;
pipes++;
}
else
argumentContainer[argCount] = argCount;

++argCount;
}

// execute commands
for (int i = 0; i <= pipes; ++i) {
// pipe and track piping
if (i < pipes) {
pipe(p1);
++openPipesCount;
}

/*************************************
SWITCH STATEMENT FOR PIPE EXECUTION
*************************************/

/*******************************************************
Using file flags:
O_CREAT: creates file if file does not already exist
O_RDONLY: Access mode for file (read only)
00700(Mode): read/write/execute permission granted
From: http://man7.org/linux/man-pages/man2/open.2.html
********************************************************/

// parent forks child for every exec()
switch (pid = fork()) {
case -1: // process error
perror("fork failed");
break;

case 0: // child process
if ((i == 0) && (inputRedirectFlag == 1)) {
int input = open(inputFile, O_RDONLY | O_CREAT);
if (input == -1) {
printf("Input file failed to open\n");
return(EXIT_FAILURE);
}
close(0);
dup(input);
close(input);
}
else if ((i == pipes) && (outputRedirectFlag == 1)) {
int output = open(outputFile, O_WRONLY | O_CREAT, 00700);
if (output < 0) {
printf("Output file failed to open\n");
return(EXIT_FAILURE);
}
close(1);
dup(output);
close(output);
}
// EXECUTE COMMAND
execvp(argv[argumentContainer[argIndex]], &argv[argumentContainer[argIndex]]);
break;

default: // parent process
if (openPipesCount > 0) {
close(p2[0]);
close(p2[1]);
}
p2[0] = p1[0];
p2[1] = p1[1];
break;
}
/*************************************
END SWITCH STATEMENT FOR PIPE EXECUTION
*************************************/

// if job is not a run-in-background process, wait for process to complete
if (backgroundJobFlag == 0)
wait((int *)0);
}

// user wishes to terminate program
if (strcmp(argv[0], "exit") == 0)
exit(0);

// clear all executed commands
for (int i = 0; i < 20; ++i)
argv[i] = 0;

wait(&status);
}
}

第一次更新/更改。多个命令正在运行,但现在我的文件重定向(用于输入)不起作用,还有其他问题:

    #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
//#include <sys/stat.h>
#include <fcntl.h>

#ifndef READ
#define READ 0
#endif

#ifndef WRITE
#define WRITE 1
#endif

int main() {
// professor-supplied variables for commands and command parsing
char *path, *argv[20], buf[80], n, *p;
int m, status, inword, continu;
int inputRedirectFlag, outputRedirectFlag, backgroundJobFlag;
int numArguments, argIndex, argCount, activeCommands, openPipesCount;
pid_t pid;
int directoryIndex, commandArchiveIndex;
int oldFileDescriptor[2], newFileDescriptor[2];
directoryIndex = 0;

while (1) {
inword = 0;
p = buf;
m = 0;
continu = 0;
numArguments = 0;
argIndex = 0;
argCount = 0;
activeCommands = 0;
openPipesCount = 0;
pid = 0;
path = (char*)0;

// required containers
int argumentContainer[20] = { 0 };
char currentDirectory[80] = { 0 };

// archive of all commands
char *commandArchive[20] = { 0 };

// redirection flags
inputRedirectFlag = 0;
outputRedirectFlag = 0;

backgroundJobFlag = 0;

// SHELL PROMPT
printf("\nshhh> ");

// COMMAND PARSING
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
}

*p++ = 0;
argv[m] = 0;

// capture all commands in command archive
while (argv[argIndex] != 0)
{
commandArchive[numArguments] = strdup(argv[argIndex]);
numArguments++;
++argIndex;
}

// capture current working directory
getcwd(currentDirectory, 80);

// user wishes to terminate program
if (strcmp(argv[0], "exit") == 0)
exit(0);

/*************************
MANAGE BUILT-IN FUNCTIONS
**************************/
// user command is "cd"
if (strcmp(argv[0], "cd") == 0) {
if (strcmp(argv[1], ".") == 0){ // this should do nothing as a command
// *path = ???
break;
}
else if (strcmp(argv[1], "..") == 0) { // this should move user up one directory
// *path = ???
// NEED TO PASS PATH HERE!
chdir(currentDirectory);
}
else {
while (argv[directoryIndex] != 0) {
getcwd(currentDirectory, 80);
// *path = ???
// NEED TO PASS PATH HERE!
chdir(argv[directoryIndex]);
++directoryIndex;
}
}
}

/********************************************
MANAGE REDIRECTION AND BACKGROUND PROCESSING
********************************************/
while (argv[argCount] != 0) {
if (strcmp(argv[argCount], "|") == 0) {
argv[argCount] = 0;
argumentContainer[activeCommands + 1] = argCount + 1;
++activeCommands;
}
else if (strcmp(argv[argCount], "<") == 0) {
path = strdup(argv[argCount + 1]);
argv[argCount] = 0;
argv[argCount + 1] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[argCount], ">") == 0) {
path = strdup(argv[argCount + 1]);
argv[argCount] = 0;
argv[argCount + 1] = 0;
outputRedirectFlag = 1;
}
else if (strcmp(argv[argCount], "&") == 0) {
argv[argCount] = 0;
backgroundJobFlag = 1;
}
else {
argumentContainer[argCount] = argCount;
}

++argCount;
}

// execute commands
for (int pipeIndex = 0; pipeIndex <= activeCommands; ++pipeIndex) {
if (pipeIndex < activeCommands) { // if user has entered multiple commands with '|'
pipe(oldFileDescriptor);
pipe(newFileDescriptor);
++openPipesCount;
}

/*************************************
SWITCH STATEMENT FOR PIPE EXECUTION
*************************************/

// capture current path
//path = getenv("PATH");

/*******************************************************
Using file flags:
O_CREAT: creates file if file does not already exist
O_RDONLY: Access mode for file (read only)
0600(Mode): owner can read/write
ddddddddddddd
********************************************************/

// parent forks child for every exec()
switch (pid = fork()) {
case -1: // process error
perror("fork failed");
break;

case 0: // child process

/****************************************************
HAVE CHILD PROCESS MANAGE REDIRECTION
****************************************************/
if ((pipeIndex == 0) && (inputRedirectFlag == 1)) {
int input = open(path, O_RDONLY | O_CREAT, 0600);
if (input == -1) {
printf("Input file failed to open\n");
return(EXIT_FAILURE);
}
//close(READ);
//dup(input);
//close(input);
dup2(input, READ);
close(input);
}
else if ((pipeIndex == activeCommands) && (outputRedirectFlag == 1)) {
int output = open(path, O_WRONLY | O_CREAT, 0600);
if (output < 0) {
printf("Output file failed to open\n");
return(EXIT_FAILURE);
}
//close(WRITE);
//dup(output);
//close(output);
dup2(output, WRITE);
close(output);
}
/****************************************************
REDIRECTION (IF APPLICABLE) EXECUTED BY CHILD PROCESS
****************************************************/

/*******************************************************************************
CHILD EXECUTES COMMAND:
*******************************************************************************/
execvp(argv[argumentContainer[pipeIndex]], &argv[argumentContainer[pipeIndex]]);
/*******************************************************************************
EXECUTION COMPLETE
*******************************************************************************/
break;

default: // parent process
if (openPipesCount > 0) { // previous command
//close(READ);
//dup(newFileDescriptor[READ]);
close(newFileDescriptor[READ]);
close(newFileDescriptor[WRITE]);
}

if (openPipesCount < activeCommands) { // more commands need to be executed
close(newFileDescriptor[READ]);
dup(newFileDescriptor[WRITE]);
close(newFileDescriptor[WRITE]);
}

oldFileDescriptor[READ] = newFileDescriptor[READ];
oldFileDescriptor[WRITE] = newFileDescriptor[WRITE];
break;
}
/***************************************
END SWITCH STATEMENT FOR PIPE EXECUTION
**************************************/

// if job is not a run-in-background process, wait for process to complete
if (backgroundJobFlag == 0)
wait((int *)0);
}

// user wishes to terminate program
if (strcmp(argv[0], "exit") == 0)
exit(0);

// clear all executed commands
for (int i = 0; i < 20; ++i)
argv[i] = 0;

wait(&status);
}
}

我知道我可能在 argumentContainer[] 或管道方面做错了什么。我只是迷路了。

更新版本(更新 2):

在与我的教授讨论我的代码后,我做了很多更改。它几乎工作。我能够通过管道传输多个命令等。但是,“wc”似乎卡住并等待 EOF (ctrl+d),并且 cd 没有更改目录。想知道我是否需要为“cd”制作一个特例/代码。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#ifndef READ
#define READ 0
#endif

#ifndef WRITE
#define WRITE 1
#endif

int main() {
/* professor-supplied variables for commands and command parsing */
char *path, *argv[20], buf[80], n, *p;
int m, status, inword, continu;

/* flags for redirection (note: C does not have type bool; using integer value 0 or 1) */
int inputRedirectFlag, outputRedirectFlag;

/* variables for piping */
int count, pipes;
pid_t pid;

/* pipes */
int l_pipe[2], r_pipe[2];

while (1) {
inword = m = continu = count = pipes = pid = 0;
p = buf;

/* required container for handling arguments */
int argumentContainer[20] = { 0 };

/* redirection flags */
inputRedirectFlag = 0;
outputRedirectFlag = 0;

/* shell prompt */
printf("\nshhh> ");

/* command parsing */
while ((n = getchar()) != '\n' || continu)
{
if (n == ' ') {
if (inword)
{
inword = 0;
*p++ = 0;
}
}
else if (n == '\n')
continu = 0;
else if (n == '\\' && !inword)
continu = 1;
else {
if (!inword)
{
inword = 1;
argv[m++] = p;
*p++ = n;
}
else
*p++ = n;
}
} /* end of command parsing */

*p++ = 0;
argv[m] = 0;

/* user wishes to terminate program */
if (strcmp(argv[0], "exit") == 0)
exit(0);

/* manage redirection */
while (argv[count] != 0) {
if (strcmp(argv[count], "|") == 0) {
argv[count] = 0;
argumentContainer[pipes + 1] = count + 1;
++pipes;
}
else if (strcmp(argv[count], "<") == 0) {
path = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
inputRedirectFlag = 1;
}
else if (strcmp(argv[count], ">") == 0) {
path = strdup(argv[count + 1]); /* copy string argument (file string) */
argv[count] = 0;
argv[count + 1] = 0;
outputRedirectFlag = 1;
}
else {
argumentContainer[count] = count;
}

++count;
} /* end of redirection management */

/* execute commands */
for (int index = 0; index <= pipes; ++index) {
if (index < pipes) { /* if user has entered multiple commands with '|' */
pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */
}

/*************************************************************************
FILE FLAG AND FILE MODE DESCRIPTION AND DETAILS:
*************************************************************************
Using file flags:
O_CREAT: creates file if file does not already exist
O_REDONLY: Acess mode for file (read only)
O_WRONLY: Access mode for file (write only)
0600(Mode): owner can read/write
From:
http://www.thinkplexx.com/learn/article/unix/command
************************************************************************
***********************************************************************/

/* switch-statement for command execution */
switch (pid = fork()) {
/* fork() error */
case -1: perror("fork failed");
break;

case 0: /* child process manages redirection and executes */
if ((index == 0) && (inputRedirectFlag == 1)) {
int input = open(path, O_RDONLY , 0600);
if (input == -1) {
printf("Input file failed to open\n");
return(EXIT_FAILURE);
}
dup2(input, READ);
close(input);
} /* end of input redirection management */
else if ((index == pipes) && (outputRedirectFlag == 1)) {
int output = open(path, O_WRONLY | O_CREAT, 0600);
if (output < 0) {
printf("Output file failed to open\n");
return(EXIT_FAILURE);
}
dup2(output, WRITE);
close(output);
} /* end of output redirection management */

/* command executed */
execvp(argv[argumentContainer[index]], &argv[argumentContainer[index]]);

/* execvp() fails */
printf("execution of command failed\n");

break;

default: /* parent process manages the pipes for child process(es) */
if (index > 0) {
close(l_pipe[READ]);
close(l_pipe[WRITE]);
}
l_pipe[READ] = r_pipe[READ];
l_pipe[WRITE] = r_pipe[WRITE];

break;
} /* end of switch-statement for command execution */
} /* end of loop for all pipes */

// user wishes to terminate program
if (strcmp(argv[0], "exit") == 0) {
exit(0);
}

// clear all executed commands
for (int i = 0; i < 20; ++i) {
argv[i] = 0;
}

wait(&status);
}
}

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com