为什么尝试文件重定向会破坏此代码?

时间:2016-02-18 02:30:59

标签: c++ linux

这基本上应该执行用户输入的linux shell命令并调用execvp 对于我的测试功能,为什么输入命令时就像'    ls -l>为sample.txt 命令不仅不会执行,而且也不会创建文件。

但是,如果我在没有重定向的情况下运行命令,它可以正常工作。

在附加了文件名的运行失败之后,shell也完全坏了,甚至以前工作的普通命令都不起作用。

似乎ls -l有时会破坏下一个输入命令。然后它变得无法找到ls或任何其他命令。

编辑:在任何失败的命令之后,它将无法完成任何以前正在运行的命令。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vector>
#include <algorithm>
#include <limits>


void testFunction(int num, char **argv, char **fname)
{
   std::cout << "vvv testFunctionBegin vvv" << std::endl;
   int status;
   int fd;

   if (fork() != 0)
   {
      std::cout << "fork() != 0" << std::endl;
      waitpid(-1, &status, 0);
   }
   else
   {
      std::cout << "fork() == 0" << std::endl;
      /*
      if (isalnum(*fname[0]) || ispunct(*fname[0]))
      {
          std::cout << "File has "<< *fname[0] << std::endl;
          fd = open(fname[0], O_WRONLY, O_APPEND, O_CREAT);
          std::cout << "fd = " << fd << std::endl;
          std::cout << "fname = " << fname[1] << std::endl;
          perror("open");
          dup2(fd, 1);
          close(fd);

      }
      */
      std::cout << "argv[0] = " << *argv[0] << std::endl;
      execvp(argv[0], argv);
   }

}

std::vector<std::string> processString(std::string userInput)
{
   int j = 0;
   std::vector<std::string> subStrs;
   for (int i = 0; i < userInput.size(); i++)
   {
      bool sameSeq = false;
      if (isalnum(userInput[i]) || ispunct(userInput[i]))
      {
         subStrs.resize(subStrs.size() + 1);
         while (isalnum(userInput[i]) || ispunct(userInput[i]))
         {
            subStrs[j].push_back(userInput[i]);
            sameSeq = true;
            //std::cout << "userInput[" << i << "] = " << userInput[i] 
            //          << " --> " << "subStrs[" << j << "] = "
            //          <<  subStrs[j] << std::endl; 
            i++;
         }
         if (sameSeq)
         {
            subStrs[j].push_back('\0');
            j++;   
         }
      }

   }
   return subStrs;
}

int main(int argc, char **argv)
{
   std::string userInput;
   std::string readySym = "$ ";
   std::vector<std::string> subStrs(1, "");
   std::vector<char*> cmdFlgs;
   std::vector<char*> fileName;

   while (true)
   {  
      std::cout << readySym;
      getline(std::cin, userInput, '\n');

      int j = 0;
      bool fileDirect = false;

      if(!userInput.empty())
      {
         // Put user input into vecotr of strings
         subStrs = processString(userInput);
         int i = 0;
         while ((i < subStrs.size()) && (subStrs[i] != ">") )
         {
            cmdFlgs.push_back(const_cast<char*>(subStrs[i].c_str()));
            i++;
         }

         /*for (int i = 0; i < cmdFlgs.size(); i++)
         {
            std::cout << "cmdFlgs[" << i << "] = " << cmdFlgs[i] << std::endl;
            std::cout << "It is: " << isspace(*cmdFlgs[i]) << std::endl;
         } 
         */
         int j = 0;
         if ( ++i < subStrs.size())
         {
            fileName.push_back(const_cast<char*>(subStrs[i].c_str()));
            std::cout << "fileName[" << i << "] = " << fileName[i] << std::endl;
         }

         testFunction(cmdFlgs.size(), cmdFlgs.data(), fileName.data());     
         fileName.clear(); 
         cmdFlgs.clear(); 
      }

   subStrs.clear();
   subStrs.resize(1);
   }

return 0;
}

2 个答案:

答案 0 :(得分:1)

您对execvp以及shell如何工作的期望是错误的。 execvp将执行给定的程序,并将其余的命令行参数作为参数传递给程序。当您在命令行上运行它时,shell会做一些工作来理解'&gt;'符号不会传递给被调用的程序,而是被解释为重定向。

答案 1 :(得分:0)

如果未输入输出重定向运算符,则fileName数组将为空。

     if ( ++i < subStrs.size())
     {
        fileName.push_back(const_cast<char*>(subStrs[i].c_str()));

如果未采用此if分支,fileName将保持完全为空的向量。 P.S。:这const_cast使我的眼睛流血。

testFunction(cmdFlgs.size(), cmdFlgs.data(), fileName.data());  
在这种情况下,

fileName.data()将是一个空指针。

您的问题是,在注释部分到位后,您的代码无效。

if (isalnum(*fname[0]) || ispunct(*fname[0]))

由于fname参数是空指针,因此这里将有一个空指针取消引用。

此外,此代码遭遇严重的C-itis案例。这是一个主要困扰C ++代码的条件,它认为它不是C ++代码,而是C代码。

例如:

subStrs[j].push_back('\0');

这完全没必要。 std::string会自动处理详细信息,例如始终在字符串末尾附加\ 0。这不再是C,这是C ++。并且,在C ++中,我们不会像将\0附加到字符串那样处理愚蠢。这是std::string的用途。

     if (sameSeq)
     {
        subStrs[j].push_back('\0');
        j++;   
     }

同样的事情。这些都不是必需的。此外,这里还有一个家庭作业。尝试找出sameSeq始终为true的原因。没有例外(免费提示,请查看前一个ifwhile条件。这里要删除更多不需要的代码。

PS。所有上述内容都是在调试器的帮助下快速确定的,即gdb,这与您的linux机箱上的gdb相同。这是您应该研究的另一件事:学习如何使用gdb