在尝试创建一个非常基本的命令行解释器时,我遇到了一个我似乎无法弄清楚的部分。当我检查令牌以获取所需的延迟时,我似乎无法正确启用&&和||功能。下面列出了插入args然后创建过程的循环。
我只专注于&&目前并计划使用该实现来帮助||功能。你们可以看看并帮助我指出正确的方向吗?
旁注:这也是我第一次用C编写程序,因此代码中可能会出现一些错误。
这是一个家庭作业问题。
由于
使用我目前为止的完整程序代码进行了更新。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define ARG_SIZE 1<<16
#define MAXLINE 100
char *args[ARG_SIZE];
int place = 0;
int return_status;
void insert( char *token ){
args[ place ] = token;
place++;
}
void create() {
size_t nargs = place;
pid_t pid;
if ( nargs == 0 ) return;
if ( !strcmp( args[0], "exit" ) ) exit(0);
pid = fork();
if ( pid ) {
pid = wait( return_status );
} else {
if ( access( args[ 0 ], X_OK ) ){
if( execvp( args[ 0 ], args ) ) {
puts( strerror( errno ) );
exit( 127 );
}
}else{
puts( strerror( errno ) );
exit( 127 );
}
}
int i = 0;
for ( i ; i < place + 1; i++)
args[ i ] = NULL;
place = 0;
}
int main( int argc, char *argv[] ){
char line[MAXLINE+1]; /* an input line */
int c; /* a single input char or EOF */
int n; /* line length */
char *token; /* pointer to an input token */
for(;;) { /* repeat until end of file */
write( 1, "#>", 2 );
if (fgets(line,MAXLINE,stdin) == NULL) /* end of file? */
exit(0);
n = strlen(line); /* get length of line */
if (n == 0) /* if line is empty */
continue;
if (line[n-1] != '\n') { /* does input end with '\n' ? */
fprintf(stderr,"Line too long.\n"); /* no, so line is too long. */
/*--------------------------------------------*/
/* Read and ignore input through end of line. */
/*--------------------------------------------*/
while ((c = fgetc(stdin)) != '\n') {
if (c == EOF) {
fprintf(stderr,"Unexpected end of file\n");
exit(1);
}
}
continue;
}
write( 1, line, strlen( line ) );
line[n-1] = '\0'; /* remove the end of line */
/*-------------------------------------------------------------*/
/* Identify and process each token (i.e. sequence of non-blank */
/* characters delimited by whitespace). For "ordinary" tokens */
/* (i.e. "words") we just display them. For the ||, &&, and ; */
/* items we display them with a textual explanation. */
/*-------------------------------------------------------------*/
token = strtok(line," \t");
while (token != NULL ) {
insert( token );
if (!strcmp(token,"&&")){
place--;
args[ place ] = NULL;
create();
if( return_status == -1)
write( 1, "Wait failed.\n", 12 );
if( return_status & 0xff ){
int i = 0;
for( i; i < place; i++)
args[ i ] = NULL;
place = 0;
while( strcmp( token, "||" ) || strcmp( token, ";" ) ) ;
}
}
else if (!strcmp(token,"||")){
place--;
args[ place ] = NULL;
completed = 0;
create();
}
else if (!strcmp(token,";")){
place--;
args[ place ] = NULL;
create();
}
else{
}
token = strtok(NULL," \t");
}
create();
}
return 0;
}
答案 0 :(得分:1)
wait()接受一个整数指针,而不是整数。应该有一个编译器警告。如果没有,我建议你使用警告标志。
#include <sys.wait.h>
wait(&return_code);
此检查不正确,因为access()在成功时返回0。似乎您不能使用访问不在当前目录中的检查命令,除非它们已经给出了可执行文件的完整路径,或者您可以扩展它。例如,“ls”需要扩展为“/ bin / ls”。
if ( access( args[ 0 ], X_OK ) ){
if( execvp( args[ 0 ], args ) ) {
puts( strerror( errno ) );
exit( 127 );
}
对return_status的检查是查看第一个字节,但forked()或execvp()的程序在第二个字节中返回其状态。检查它返回的内容:
if( return_status & 0xff ){
应该是:
if ( WEXITSTATUS(return_status) != 0 ){
或
if ( (return_status & 0xff00) >> 8 ){
if body:
for( int i = 0; i < place; i++)
args[ i ] = NULL;
place = 0;
while( strcmp( token, "||" ) || strcmp( token, ";" ) ) ;
可以替换为:
break;
因为你正在执行for循环并在create()中将place设置为0,而while循环对我来说是无限的。刚刚结束封闭,同时结束命令序列,让你回到读取另一个输入的命令行。
//if ( return_status == -1)
可以使用wait()状态宏:
if ( ! WIFEXITED(return_status) )
答案 1 :(得分:0)
此代码显示了我在其他答案中提到的内容,适用于“false&amp;&amp; ls”并更新以解决&amp;&amp; amp;之后的其他命令。失败。
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define ARG_SIZE 1 << 16
#define MAXLINE 100
char *args[ARG_SIZE];
int place = 0;
int return_status;
char message[200];
void insert( char *token ){
args[ place ] = token;
place++;
}
void reset_args(void)
{
for (int i = 0 ; i < place + 1; i++)
args[ i ] = NULL;
place = 0;
}
#define EXECVP_FAILED 127
char last_command[200];
void create() {
size_t nargs = place;
pid_t pid;
if ( nargs == 0 ) return;
if ( args[0] )
strcpy(last_command,args[0]);
else
last_command[0] = '\0';
if ( !strcmp( args[0], "exit" ) ) exit(0);
pid = fork();
if ( pid ) {
pid = wait( &return_status );
} else {
if( execvp( args[ 0 ], args ) )
{
puts( strerror( errno ) );
exit( EXECVP_FAILED );
}
}
reset_args();
}
int main( void ){
char line[MAXLINE+1]; /* an input line */
int c; /* a single input char or EOF */
int n; /* line length */
char *token; /* pointer to an input token */
enum states { NORMAL, AND_CMD_FAILED };
enum states state = NORMAL;
for(;;) { /* repeat until end of file */
state = NORMAL;
write( 1, "#>", 2 );
if (fgets(line,MAXLINE,stdin) == NULL) /* end of file? */
exit(0);
n = strlen(line); /* get length of line */
if (n == 0) /* if line is empty */
continue;
if (line[n-1] != '\n') { /* does input end with '\n' ? */
fprintf(stderr,"Line too long.\n"); /* no, so line is too long. */
/*--------------------------------------------*/
/* Read and ignore input through end of line. */
/*--------------------------------------------*/
while ((c = fgetc(stdin)) != '\n') {
if (c == EOF) {
fprintf(stderr,"Unexpected end of file\n");
exit(1);
}
}
continue;
}
write( 1, line, strlen( line ) );
line[n-1] = '\0'; /* remove the end of line */
/*-------------------------------------------------------------*/
/* Identify and process each token (i.e. sequence of non-blank */
/* characters delimited by whitespace). For "ordinary" tokens */
/* (i.e. "words") we just display them. For the ||, &&, and ; */
/* items we display them with a textual explanation. */
/*-------------------------------------------------------------*/
token = strtok(line," \t");
while (token != NULL ) {
insert( token );
if (!strcmp(token,"&&")){
place--;
args[ place ] = NULL;
if ( state == NORMAL )
create();
else
reset_args();
if ( ! (WIFEXITED(return_status) ) || ( WEXITSTATUS(return_status) ) )
{
// command did not execute successfully
if ( ! WIFEXITED(return_status) )
{
sprintf(message,"Wait failed for %s\n",last_command);
write( 1, message, strlen(message) );
}
else if ( WEXITSTATUS(return_status) == EXECVP_FAILED )
{
sprintf(message,"execvp failed for %s\n",last_command);
write( 1, message, strlen(message) );
}
else if ( WEXITSTATUS(return_status) != 0 ) {
sprintf(message,"%s command failed - exit status %d\n",
last_command,WEXITSTATUS(return_status));
write( 1, message, strlen(message) );
}
// bypass next command(s) up to || or ; delimiters
state = AND_CMD_FAILED;
}
}
else if (!strcmp(token,"||")){
place--;
args[ place ] = NULL;
//completed = 0;
if ( state == NORMAL )
create();
else
reset_args();
state = NORMAL;
}
else if (!strcmp(token,";")){
place--;
args[ place ] = NULL;
if ( state == NORMAL )
create();
else
reset_args();
state = NORMAL;
}
else{
}
token = strtok(NULL," \t");
}
if ( state == NORMAL )
create();
else
reset_args();
}
return 0;
}