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

Why does attempted file redirection break this code?

本文关键字:代码 重定向 文件 为什么      更新时间:2023-10-16

这基本上应该执行用户输入的 Linux shell 命令并调用 execvp对于我的测试函数,为什么在输入命令时会像" ls -l>样本.txt命令不仅不执行,而且文件也不会创建。

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

此外,在附加文件名的失败运行后,shell 会完全损坏,即使是以前有效的正常命令也无法正常工作。

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

编辑:在任何失败的命令之后,它将无法 fin 任何以前工作的命令。

#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('');
            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;
}

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

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

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

如果不采用此if分支,fileName将保持为完全空的向量。PS:这个const_cast让我的眼睛流血。

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

在这种情况下,fileName.data() 将是一个空指针。

您的

问题是,在注释部分到位的情况下,您的代码不起作用。

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

由于 fname 参数是空指针,因此此处将取消引用空指针。

此外,此代码正在遭受严重的C-it情况。这种情况主要困扰C++认为它不是C++代码而是 C 代码的代码。

例如:

subStrs[j].push_back('');

这是完全没有必要的。 std::string会自动处理详细信息,例如始终在字符串末尾附加 \0。这不再是C,这是C++。而且,在C++中,我们不会处理像将附加到字符串之类的愚蠢行为。这就是std::string的目的。

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

同样的事情。这些都不需要。此外,这是适合您的家庭作业。试着弄清楚为什么sameSeq总是在这里true。没有例外(免费线索,查看前面的ifwhile条件)。只是更多不需要的代码要删除,在这里。

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