C++ I/O重定向,打印到错误的文件描述符
我正在处理管道和其他文件描述符,结果遇到了麻烦 一些背景 对于某些人来说,下面的函数使用基于上下文的文件描述符重复执行execvp调用。这样(理想情况下)调用就可以很容易地串在一起进行i/o重定向 例如,一个可能的输入可能如下所示:C++ I/O重定向,打印到错误的文件描述符,c++,linux,unix,io-redirection,C++,Linux,Unix,Io Redirection,我正在处理管道和其他文件描述符,结果遇到了麻烦 一些背景 对于某些人来说,下面的函数使用基于上下文的文件描述符重复执行execvp调用。这样(理想情况下)调用就可以很容易地串在一起进行i/o重定向 例如,一个可能的输入可能如下所示: cat < input.txt | tr a-z A-Z cat
cat < input.txt | tr a-z A-Z
cat
此函数之外的解析器将转换为:
argvv.at(0).first = "cat", NULL
argvv.at(0).second.at(0) = "1" //this lets us easily see what fd this 'chunk' is using. In my code, 1 stands for "<"
argvv.at(0).second.at(1) = "input.txt" // the file to be read from
argvv.at(1).first = "tr", "a-z", "A-Z", NULL;
argvv.at(1).second.at(0) = "4" // in my code, 4 stands for |
argvv.at(0).first=“cat”,NULL
argvv.at(0).second.at(0)=“1”//这让我们很容易看到这个“块”在使用什么。在我的代码中,1代表“这是维姆的结果,但你是对的。我会把它编辑掉,我看不出有什么问题,也不知道这和C作为编程语言有什么关系。请修改你的标签并提出你的问题的更简洁的描述。“J.S.GugSistt我认为从我使用系统调用以来就包含C是明智的,但是你是对的,代码是用C++编写的,所以我想标签不是完全相关的。”JensGustedt,我也认为我把这个问题弄得非常清楚。但我现在用粗体字写了。
(cat < input.txt) (| tr a-z A-Z)
argvv[0] ^ argvv[1] ^
int fcall(std::vector < std::pair<char**, std::vector <std::string> > > argvv ){
const int pipew = 1;
const int piper = 0;
//gotta say, fully understanding pipe I really appriciate how much sense this saves me.
int status;
if (strlen(argvv.at(0).first[0]) == 0){
return -1;
}
if (!strcmp(argvv.at(0).first[0], "exit")){
return 1;
}
//counter of weights
unsigned int waitcount = 0;
int n = 0;
std::vector<int*> fdv;
for (unsigned int k = 0; k < argvv.size(); k++){
if (!argvv.at(k).second.at(0).compare("4") ){ //figures out how many pipes we'll need
int fd[2];
if(pipe(fd) == -1)
perror("pipe");
fdv.push_back(fd);
}
else
{
fdv.push_back(NULL);
}
if(argvv.at(k).second.at(0).compare("2") && argvv.at(k).second.at(0).compare("3")){ //determines how long we should be waiting
waitcount++;
}
}
int stdins;
int stdouts;
if (-1 == (stdins = dup(0)))
perror("dup");
if (-1 == (stdouts = dup(1)))
perror("dup");
for (unsigned int i = 0; i < argvv.size(); i++ ){
int pid = fork();
if(pid == -1)//fork’s return value for an error is -1
{
//perror("There was an error with fork(). ");
perror("fork"); //although you certainly can use the above, it is good
//practice not to write more information than necessary
exit(1);//there was an error with fork so exit the program and go back and fix it
}
else if(pid == 0)//when pid is 0 you are in the child process
{
int fdx;
int fdy;
//(I) ==============
int y = ((int)argvv.at(i).second.at(0).at(0)-48);
std::cerr << y << std::endl;
switch (y){
case 0:
break;
case 1:
if (-1 == (fdy = open(argvv.at(i).second.at(1).c_str(), O_RDONLY))){
perror("open");
}
if (-1 == dup2(fdy, 0)){
perror("dup");
}
break;
case 2:
break;
case 3:
break;
case 4:
if(-1 == dup2(fdv.at(i)[piper],0 ))
perror("dup");
break;
}
//(I +1) ==============
if (i+1 < argvv.size()){
int z = ((int)argvv.at(i+1).second.at(0).at(0)-48);
std::cerr << std::endl;
switch (z){
case 0:
break;
case 1:
break;
case 2:
if (-1 == (fdx = open(argvv.at(i+1).second.at(1).c_str(), O_RDWR | O_CREAT,S_IRWXU ))){
perror("open");
}
if (-1 == dup2(fdx,1 ))
perror("dup");
break;
case 3:
if (-1 == (fdx = open(argvv.at(i+1).second.at(1).c_str(), (O_RDWR | O_APPEND) | O_CREAT,S_IRWXU ))){
perror("open");
}
if (-1 == dup2(fdx,1 ))
perror("dup");
break;
case 4:
if(-1 == dup2(fdv.at(i+1)[pipew],1 ))
perror("dup");
break;
}
}
for(unsigned int kg; kg < fdv.size(); kg++){
if (fdv.at(kg) != NULL){
if (-1 == close(fdv.at(kg)[0]))
perror("close");
if (-1 == close(fdv.at(kg)[1]))
perror("close");
}
}
if (y != 2 && y!= 3){
if (0 < execvp(argvv.at(i).first[0],argvv.at(i).first )){
n = -1;
perror("execvp");
}
}
exit(1); //when the child process finishes doing what we want it to, cout,
//we want to kill the child process so it doesn’t go on in the program so we exit
}
}
for (unsigned int f = 0; f < waitcount; f++){
if (-1 == wait(&status))
perror("wait");
}
if (-1 == dup2(stdins, 0))
perror("dup");
if (-1 == dup2(stdouts, 1))
perror("dup");
if (-1 == close(stdins))
perror("close");
if (-1 == close(stdouts))
perror("close");
return n;
}