【问题标题】:Bad 'ls' Command Behavior In Custom Simple Shell自定义简单外壳中的错误“ls”命令行为
【发布时间】:2015-11-26 01:45:50
【问题描述】:

我遇到的问题似乎超出了我的认知。我正在编写一个简单的 shell 来学习一些系统编程,以便在 Unisys 实习。在我的 shell 中,我尝试的所有命令似乎都在运行,除了 ls 甚至现在发现了 wc 命令。 lswc 在我自己键入时有效,但如果我给它参数,它将无法工作并给我一个错误提示 No such file or directory

这是我的代码:

#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#define BUF_SIZE 1024
#define DELIMS " -\r\t\n"

/****************************************************************
 *  Capture input from the user. Returns the input from the
 *  standard input file descriptor.
 ***************************************************************/
char * getInput (char **buffer, size_t buflen)
{
    size_t bufsize = BUF_SIZE;
    *buffer = malloc(sizeof(char) * bufsize + 1);   // allocate space for the buffer

    if (!*buffer)
    {
        fprintf(stderr, "Shell: buffer allocation error\n");
        exit(EXIT_FAILURE);
    }

    printf("$$ ");

    fflush(NULL);

    int bytesRead = getline(&(*buffer), &bufsize, stdin);
    if (bytesRead < 0)
    {
        printf("Getline error\n");
        exit(EXIT_FAILURE);
    }

    return *buffer; // Not capturing return value right now
 }

/****************************************************************
 *  Tokenize the buffer input from stdin
 ***************************************************************/
char ** splitLine(char *line)
{
    int bufsize = BUF_SIZE;
    int pos = 0;
    char **tokens = malloc (sizeof(char) * BUF_SIZE + 1);
    char *token;

    if (!tokens)
    {
        fprintf(stderr, "Shell: buffer allocation error\n");
        exit(EXIT_FAILURE);
    }

    /* Tokenize the line */
    token = strtok(line, DELIMS);
    while (token != NULL)
    {
        tokens[pos] = token;
        pos++;
        if (pos > bufsize)
        {
            bufsize += BUF_SIZE;
            tokens = realloc(tokens, bufsize * sizeof(char) + 1);
            if (!tokens)
            {
                fprintf(stderr, "Shell: buffer allocation error\n");
                exit(EXIT_FAILURE);
            }
        }
        token = strtok(NULL, DELIMS);   // continue grabbing tokens
    }

    tokens[pos] = NULL;
    return tokens;
}

/****************************************************************
 *  Main function
 ***************************************************************/
int main (int argc, char **argv)
{
    char *buf;     // buffer to hold user input from standard input stream.
    pid_t pid;          // Parent id of the current process
    int status;

    /* Loop while the user is getting input */
    while (getInput(&buf, sizeof(buf)))
    {
        char **args = splitLine(buf);
        int i = 0;

        /* Print tokens just to check if we are processing them correctly */
        while (1)
        {
            char *token = args[i++];
            if (token != NULL)
                printf("Token #%d: %s\n", i, token);
            else
                break;
        }

        fflush(NULL);

        /* Fork and execute command in the shell */
        pid = fork();
        switch(pid)
        {
            case -1:
            {
                /* Failed to fork */
                fprintf(stderr, "Shell cannot fork: %s\n", strerror(errno));
                continue;
            }
            case 0:
            {
                /* Child so run the command */
                execvp(args[0], args);        // Should not ever return otherwise there was an error
                fprintf(stderr, "Shell: couldn't execute %s: %s\n   ", buf, strerror(errno));
                exit(EX_DATAERR);
            }
        }

        /* Suspend execution of calling process until receiving a status message from the child process
            or a signal is received. On return of waitpid, status contains the termination
            information about the process that exited. The pid parameter specifies the set of child
            process for which to wait for */
        if ((pid = waitpid(pid, &status, 0) < 0))
        {
            fprintf(stderr, "Shell: waitpid error: %s\n", strerror(errno));
        }

        free(args);
    }

    free(buf);

    exit(EX_OK);
}

例如,我尝试了以下带有输出的命令:

ls -la(问题)

$$ ls -la
Token #1: ls
Token #2: la
ls: la: No such file or directory
$$ 

wc -l(问题)

$$ wc -l
Token #1: wc
Token #2: l
wc: l: open: No such file or directory

ls

$$ ls
Token #1: ls
Makefile    driver      driver.dSYM main.c      main.o
$$ 

ps -la

$$ ps -la
Token #1: ps
Token #2: la
  UID   PID  PPID CPU PRI NI      VSZ    RSS WCHAN  STAT   TT       TIME COMMAND
    0  2843  2405   0  31  0  2471528      8 -      Us   s000    0:00.08 login 
  501  2845  2843   0  31  0  2463080   1268 -      S    s000    0:01.08 -bash
  501  4549  2845   0  31  0  2454268    716 -      S+   s000    0:00.01 ./driv
    0  4570  4549   0  31  0  2435020    932 -      R+   s000    0:00.00 ps la
$$

哪个

$$ which which
Token #1: which
Token #2: which
/usr/bin/which

哪个-a哪个

$$ which -a which 
Token #1: which
Token #2: a
Token #3: which
/usr/bin/which

甚至最后ma​​n getline

GETLINE(3)               BSD Library Functions Manual               GETLINE(3)

NAME
     getdelim, getline -- get a line from a stream

LIBRARY
     Standard C Library (libc, -lc)
.
.
.

谁能帮我指出我为什么会遇到这个问题?

【问题讨论】:

  • 只看你的输出,你从命令行选项中丢失了-,所以在第一个例子中你实际上是在做一个ls la,这将在bash中给出同样的错误. ps 有效,因为 ps 在没有 - 的情况下有一些选项。
  • 更进一步,@blm 说的是,你有 #define DELIMS " -\r\t\n" 并且你正在使用 strtok()。从分隔符列表中删除破折号。

标签: c linux bash shell


【解决方案1】:

您在 DELIMS 宏中添加了“-”作为单词分隔符。

删除它应该可以解决您的问题。

顺便说一句,最好避免使用可以轻松做到的宏。在这里,我会使用const char* delims 来存储分隔符。我通常发现声明一个靠近其使用位置的变量更容易 - 我认为这更容易发现错误和阅读代码。

【讨论】:

  • 哎呀!对不起那个家伙。我太笨了哈哈。这解决了这个问题。非常感谢您为我指出这一点。天哪,抱歉浪费你们的时间了:(
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 2021-03-27
相关资源
最近更新 更多