问题描述
我必须使用 c 中的管道来模拟这个命令:echo "
代码是这样的,但我不明白为什么它不起作用;特别是,“bc”命令似乎无法从标准输入中读取表达式。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define LEGGI(stringa) if(scanf("%s",stringa) == 0) \
{ \
perror("Impossibile leggere la stringa"); \
exit(EXIT_FAILURE); \
} \
void closePipe(int pipeFd);
void Dup2(int pipeTempFd,int fd);
void Write(int pipeTempFd,char stringa[],int n);
void Read(int pipeTempFd,int n);
int main()
{
char stringa[N];
LEGGI(stringa);
int pipeFd[2];
int pRicezioneFd[2];
if(pipe(pipeFd) == -1 || pipe(pRicezioneFd) == -1)
{
perror("impossibile eseguire la pipe");
exit(EXIT_FAILURE);
}
if(strncmp(stringa,"exit",N) != 0)
{
pid_t processpid;
if((processpid = fork()) == 1)
{
perror("impossibile eseguire la fork");
exit(EXIT_FAILURE);
}
if(processpid != 0)
{
closePipe(pipeFd[0]);
closePipe(pRicezioneFd[1]);
printf("operazione: %s\n",stringa);
Write(pipeFd[1],stringa,N);
closePipe(pipeFd[1]);
read(pRicezioneFd[0],N);
closePipe(pRicezioneFd[0]);
if(wait(NULL) == -1)
{
perror("Impossibile eseguire la wait");
exit(EXIT_FAILURE);
}
printf("%s\n",stringa);
}
else
{
closePipe(pipeFd[1]);
closePipe(pRicezioneFd[0]);
Dup2(pipeFd[0],0);
Dup2(pRicezioneFd[1],1);
Dup2(pRicezioneFd[1],2);
// closePipe(pipeFd[0]);
// closePipe(pRicezioneFd[1]);
if(execl("/usr/bin/bc","bc","-lq",NULL) == -1)
{
perror("programma non reperibile");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
void closePipe(int pipeFd)
{
if(close(pipeFd) == -1)
{
perror("impossibile chiudere il fd della pipe");
exit(EXIT_FAILURE);
}
}
void Dup2(int pipeTempFd,int fd)
{
if(dup2(pipeTempFd,fd) == -1)
{
perror("Impossibile eseguire la dup2");
exit(EXIT_FAILURE);
}
}
void Write(int pipeTempFd,int n)
{
if(write(pipeTempFd,n) == -1)
{
perror("impossibile scrivere sulla pipa");
exit(EXIT_FAILURE);
}
}
void Read(int pipeTempFd,int n)
{
if(read(pipeTempFd,n) == -1)
{
perror("impossibile leggere dalla pipe pipa");
exit(EXIT_FAILURE);
}
}
解决方法
您正在将大部分未初始化的 stringa 的所有 1024 字节写入 bc
,然后会因非法字符而窒息。 bc
期望换行终止,“纯文本”表达式。
#define N 1024
char stringa[N]; // stringa := "\236\0\0\241\177>\0\0\3704\241..."
scanf("%s",stringa); // stringa := "1+2\0\177>\0\0\3704\241..."
// ^^^^^^^^^^^^^^^^^^^^
....
Write(pipeFd[1],stringa,N); // ohimè!
你会想要这样的:
Write(pipeFd[1],strlen(stringa));
Write(pipeFd[1],"\n",1);
,
我认为我的代码与您的相似,一个主要变化是 exec 调用的参数。另一个变化是我在子进程中只有 2 个 dup2 调用,一个用于更改标准输入,另一个用于标准输出。你只需要改变这些。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#define N 1024
#define READ_END 0
#define WRITE_END 1
int main()
{
char *input = NULL;
size_t len = 0;
ssize_t amt_read = 0;
puts("Please enter a string: ");
amt_read = getline(&input,&len,stdin);
if(amt_read < 0)
exit(EXIT_FAILURE);
pid_t pid;
int fd[2];
int fd_return[2];
// Create the pipes
pipe(fd);
pipe(fd_return);
pid = fork();
if(pid==0)
{ // If child process
dup2(fd[READ_END],STDIN_FILENO);
dup2(fd_return[WRITE_END],STDOUT_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
close(fd_return[WRITE_END]);
close(fd_return[READ_END]);
execl("/usr/bin/bc","/usr/bin/bc","-lq",(char *)NULL);
fprintf(stderr,"Failed to execute\n");
exit(EXIT_FAILURE);
}
else
{ // If parent process
int status;
close(fd[READ_END]);
close(fd_return[WRITE_END]);
// Write to the pipe
write(fd[WRITE_END],input,strlen(input));
close(fd[WRITE_END]);
// Wait for the child to finish
waitpid(pid,&status,0);
char buff[N];
buff[N-1] = 0;
read(fd_return[READ_END],buff,N-1);
*(index(buff,'\n')) = '\0'; // Add null terminator on your own
close(fd_return[READ_END]);
printf("The Result is: %s\n",buff);
}
free(input);
return 0;
}
编辑: 我编辑了代码并调试了它。我还更改了用户输入原理图,因此现在您不再为用户输入分配静态存储,而是动态分配,然后在最后使用 free() 释放此存储;
请注意,我确实保留了用于读取输入的静态存储,如果您愿意,可以在将来更改此设置。
非法字符:^@来自write()写太多,注意现在我们只写strlen(buff)数量。
注意:除非字符串以 "...\n\0" 结尾,幸运的是 getline() 默认情况下会这样做,否则 bc 的输入将不起作用。
另外,我让所有的管道都关闭了,这并没有导致问题。