【问题标题】:Unix shell's input redirection not workingUnix shell 的输入重定向不起作用
【发布时间】:2016-02-20 13:08:30
【问题描述】:

我发现了同样的问题,但没有答案。

在构建我自己的 unix shell 时,我的输出重定向工作正常,但是当我尝试输入时,它什么也没做。如果你能帮我找出问题,那就太好了。 这是我的 exec 函数代码:

void execute (char **args)
{
   int pid, status;
   pid = fork ();

   if (pid < 0) 
   {
      perror ("Error forking!");
      return;
   }


   else if (pid > 0) 
   {
      fflush(0);
      while (wait (&status) != pid)
         continue;
   }


   else if (pid == 0) 
   {

      int i,in=0,out=0;
      char input[BUF_SIZE],output[BUF_SIZE];

      for(i=0;args[i]!=NULL;i++)
      {
         if(strcmp(args[i],"<")==0)
         {        
            args[i]=NULL;
            strcpy(input,args[i+1]);
            in=2;           
         }               

         if(strcmp(args[i],">")==0)
         {      
            args[i]=NULL;
            strcpy(output,args[i+1]);
            out=2;
         }         
      }


      if(in)
      {   
         int fd0;
         if ((fd0 = open(input, O_RDONLY, 0)) < 0) 
         {
            perror("Couldn't open input file");
            exit(0);
         }           

         dup2(fd0, 0); 

         close(fd0); 
      }


      if (out)
      {
         int fd1;
         if ((fd1 = creat(output , 0644)) < 0) 
         {
            perror("Couldn't open the output file");
            exit(0);
         }           

         dup2(fd1, 1); 
         close(fd1);
      }

      execvp (*args, args);
      perror("execvp");
      _exit(1);
   }

这是我的全部代码:

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

#define ARGSIZE 20
#define BUF_SIZE 1024

void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);

int main (void)
{
    char line[BUF_SIZE] = {0};
    char *args[ARGSIZE] = {NULL};
    char *token;
    int i, argIndex = 0;

    while (1) 
    {

        argIndex = 0; 

        for (i = 0; i < ARGSIZE; i++)
            args[i] = NULL;

        printf ("shell> "); 

        if (fgets (line, BUF_SIZE, stdin) == NULL) 
        {
            printf ("EOF received\n");
            return 0;
        }

        if (*line == '\n') 
        continue;

        token = strtok (line, " \n"); 

        while (token != NULL) 
        {
            args[argIndex] = token;
            token = strtok (NULL, " \n");
            argIndex++;
        }

        if (!argIndex)
            continue;  

        if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
            break;

        if ((strcmp (args[0], "cd") == 0))
            cd (args[1]);
        else if ((strcmp (args[0], "kill") == 0)) 
        {
            if (args[1])
                killpid (args[1], SIGTERM);
        }


        else
            execute (args);

    }
    return 0;
}

void execute (char **args)
{
    int pid, status;
    pid = fork ();

    if (pid < 0) 
    {
        perror ("Error forking!");
        return;
    }


    else if (pid > 0) 
    {
        fflush(0);
        while (wait (&status) != pid)
            continue;
    }


    else if (pid == 0) 
    {

        int i,in=0,out=0;
        char input[BUF_SIZE],output[BUF_SIZE];

        for(i=0;args[i]!=NULL;i++)
        {
            if(strcmp(args[i],"<")==0)
            {        
                args[i]=NULL;
                strcpy(input,args[i+1]);
                in=2;           
            }               

            if(strcmp(args[i],">")==0)
            {      
                args[i]=NULL;
                strcpy(output,args[i+1]);
                out=2;
            }         
        }


        if(in)
        {   
            int fd0;
            if ((fd0 = open(input, O_RDONLY, 0)) < 0) 
            {
                perror("Couldn't open input file");
                exit(0);
            }           

            dup2(fd0, 0); 
            close(fd0); 
        }


        if (out)
        {
            int fd1;
            if ((fd1 = creat(output , 0644)) < 0) 
            {
                perror("Couldn't open the output file");
                exit(0);
            }           

            dup2(fd1, 1); 
            close(fd1);
        }

        execvp (*args, args);
        perror("execvp");
        _exit(1);
        }

}

void cd (char *directory)
{
    char dir[BUF_SIZE] = {0};

    if (!directory) 
    {  
        directory = getenv ("HOME");

        if (chdir (directory))
            fprintf (stderr, "Failed to enter directory: %s\n", directory);
        else
            printf ("%s\n", directory);

        return;
    }

    if (*directory == '~') 
    { 
        strcpy (dir, getenv ("HOME"));
        strcat (dir, "/");
        strcat (dir, directory + 2);

        if (chdir (dir))
            fprintf (stderr, "Failed to enter directory: %s\n", dir);
        else
            printf ("%s\n", dir);

        return;
    }

    if (chdir (directory)) 
        fprintf (stderr, "Failed to enter directory: %s\n", directory);
    else
        printf ("%s\n", directory);
}

int killpid (char *pidstr, int sig)
{
    pid_t pid = (pid_t)atoi (pidstr);

    if (pid < 1) 
    {
        fprintf (stderr, "warning: requested pid < 1, ignoring\n");
        return (int)pid;
    }

    printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
    return 0;
}

【问题讨论】:

  • 这是 C 还是 C++ 还是别的什么?
  • execvp(...) 替换为int c; while((c = getchar()) != EOF) putchar(c); 并使用结果编辑您的问题。
  • 它是 C,我很抱歉我的大学服务器在 atm 关闭,所以我无法运行它,但它是如何工作的?它会打印文件内容但不会执行命令......比我的输出不起作用。我必须能够执行“ls -al > out.txt”这行得通,但“sort
  • 设置args[]数组时,最后一个条目必须包含NULL,但是,在发布的代码中,只有当从用户读取的行包含&lt;或@时才会发生这种情况987654327@.
  • 发布的代码包含cdkilldir 的特殊功能,但是dir 的代码中没有检查,因此用户将永远无法访问该功能.

标签: c shell unix io-redirection


【解决方案1】:

当您在此处的 args 数组中看到 &lt;

if(strcmp(args[i],"<")==0)

您将 args[i] 设置为 NULL

    args[i]=NULL;

然后,你将它传递给strcmp()

if(strcmp(args[i],">")==0)

您的子进程会很高兴地出现段错误。在此处使用if-else-construct:

if(strcmp(args[i],"<")==0) {        
    args[i]=NULL;
    strcpy(input,args[i+1]);
    in=2;           
} else if(strcmp(args[i],">")==0) {      
    args[i]=NULL;
    strcpy(output,args[i+1]);
    out=2;
}

这应该可以修复错误。

此外,这可能有助于检测此类情况:

...
while (wait (&status) != pid)
     continue;
if (WIFSIGNALED(status))
     printf("Killed by signal %d%s\n",
            WTERMSIG(status), WCOREDUMP(status)?" (Core dumped)":"");

【讨论】:

  • 您遇到了一个问题(不一定是唯一的问题),但是“将参数设置为 null”意味着 shell 命令将忽略任何后续参数。在 POSIX shell 中,您可以在输入行的任意点使用 I/O 重定向编写“&lt; input &gt; output command-name arg1 arg2”(因此“&gt; output command-name 2&gt;/dev/null arg1 &lt; input arg2”也可以使用)。除非所有 I/O 重定向都在最后一个命令参数之后,否则切换参数指针会丢失命令的参数(在极端情况下,会丢失命令)。重定向 args 需要被移除,其他的需要洗牌。
  • @JonathanLeffler 由于循环没有终止,它在我所见的范围内找到后续的输出重定向。好的,您的意思是重定向后的常规参数被忽略。这是真的,但我会说这种行为是 shell 设计师的性格。
  • 是的,shell会找到它,但是execvp()会在第一个空指针处停止处理命令行;之后它不会寻找额外的参数。所以,如果你有command-name &lt; input arg1 arg2,内核不会将arg1arg2 传递给命令。
  • 非常感谢!!!最后..我现在感觉自己像个智障哈哈。哦,我明白了,所以我每行只能使用一个重定向和一个参数.. 一开始没关系。
猜你喜欢
  • 1970-01-01
  • 2012-02-23
  • 2021-04-20
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 2020-04-16
相关资源
最近更新 更多