在阅读了一些答案之后,我的修改后的代码是:
int pid = fork();
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
if (in) { //if '<' char was found in string inputted by user
int fd0 = open(input, O_RDONLY, 0);
dup2(fd0, STDIN_FILENO);
close(fd0);
in = 0;
}
if (out) { //if '>' was found in string inputted by user
int fd1 = creat(output, 0644);
dup2(fd1, STDOUT_FILENO);
close(fd1);
out = 0;
}
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
free(res);
}
Run Code Online (Sandbox Code Playgroud)
它可以工作,但似乎标准输出没有被重新连接或者那种效果.这是执行:
SHELL$ cat > file
hello, world
this is a test
SHELL$ cat < file //no output
SHELL$ ls //no output
Run Code Online (Sandbox Code Playgroud)
'<'和'>'都有效,但在执行后没有输出.
我已经在C中使用了一个相对简单的shell一段时间了,但我在实现input(<)和output(>)重定向时遇到了麻烦.帮我找到以下代码中的问题:
int fd;
int pid = fork();
int current_out;
if (in) { //if '<' char was found in string inputted by user
fd = open(input, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
in = 0;
current_out = dup(0);
}
if (out) { //if '>' was found in string inputted by user
fd = creat(output, 0644);
dup2(fd, STDOUT_FILENO);
out = 0;
current_out = dup(1);
}
if (pid == -1) {
perror("fork");
} else if (pid == 0) {
execvp(res[0], res);
perror("execvp");
_exit(1);
} else {
waitpid(pid, 0, 0);
dup2(current_out, 1);
free(res);
}
Run Code Online (Sandbox Code Playgroud)
我可能在那里有一些不必要的材料,因为我一直在尝试不同的东西来让它发挥作用.我不确定出了什么问题.
Jon*_*ler 15
重定向后,您有太多文件描述符打开.让我们剖析这两段:
if (in) { //if '<' char was found in string inputted by user
fd = open(input, O_RDONLY, 0);
dup2(fd, STDIN_FILENO);
in = 0;
current_in = dup(0); // Fix for symmetry with second paragraph
}
if (out) { //if '>' was found in string inputted by user
fd = creat(output, 0644);
dup2(fd, STDOUT_FILENO);
out = 0;
current_out = dup(1);
}
Run Code Online (Sandbox Code Playgroud)
我将成为慈善机构并忽略你忽略错误这一事实.但是,您需要错误检查系统调用.
在第一段中,您打开一个文件并捕获变量中的文件描述符(可能是3)fd.然后,您通过标准输入(STDIN_FILENO)复制文件描述符.但请注意,文件描述符3仍处于打开状态.然后你做一个dup(0)(为了保持一致性STDIN_FILENO),得到另一个文件描述符,也许是4.所以你有文件描述符0,3和4指向同一个文件(事实上,相同的打开文件描述 - 注意到打开的文件描述与打开的文件描述符不同.如果您的意图current_in是保留(父)shell的标准输入,则必须在执行覆盖输出dup()之前执行此操作dup2().但是,最好不要改变父shell的文件描述符; 它比重新复制文件描述符的开销更少.
然后你或多或少地重复第二段中的过程,首先覆盖文件描述符3的唯一记录,该记录是通过fd = creat(...)调用打开但是获得一个新的描述符,可能是5,然后通过标准输出复制它.然后你做一个dup(1),产生另一个文件描述符,也许是6.
因此,您将主shell的stdin和stdout重定向到文件(并且无法将这些重新定位到原始值).因此,您的第一个问题是您正在进行重定向fork(); 你应该在之后这样做fork()- 虽然当你在进程之间进行管道连接时,你需要在分叉之前创建管道.
你的第二个问题是你需要关闭过多的文件描述符,其中一个你不再有参考.
所以,你可能需要:
if ((pid = fork()) < 0)
...error...
else if (pid == 0)
{
/* Be childish */
if (in)
{
int fd0 = open(input, O_RDONLY);
dup2(fd0, STDIN_FILENO);
close(fd0);
}
if (out)
{
int fd1 = creat(output , 0644) ;
dup2(fd1, STDOUT_FILENO);
close(fd1);
}
...now the child has stdin coming from the input file,
...stdout going to the output file, and no extra files open.
...it is safe to execute the command to be executed.
execve(cmd[0], cmd, env); // Or your preferred alternative
fprintf(stderr, "Failed to exec %s\n", cmd[0]);
exit(1);
}
else
{
/* Be parental */
...wait for child to die, etc...
}
Run Code Online (Sandbox Code Playgroud)
在执行任何此操作之前,您应该确保已经刷新了shell的标准I/O通道,可能是通过使用fflush(0),以便如果分叉的子进程由于问题而写入标准错误,则不会有无关的重复输出.
另请注意,open()应对错误检查各种调用.
重定向后,您有太多文件描述符打开.你需要的代码就是这个.
if (pid == 0)
{ /* for the child process: */
// function for redirection ( '<' , '>' )
int fd0,fd1,i,in=0,out=0;
char input[64],output[64];
// finds where '<' or '>' occurs and make that argv[i] = NULL , to ensure that command wont't read that
for(i=0;argv[i]!='\0';i++)
{
if(strcmp(argv[i],"<")==0)
{
argv[i]=NULL;
strcpy(input,argv[i+1]);
in=2;
}
if(strcmp(argv[i],">")==0)
{
argv[i]=NULL;
strcpy(output,argv[i+1]);
out=2;
}
}
//if '<' char was found in string inputted by user
if(in)
{
// fdo is file-descriptor
int fd0;
if ((fd0 = open(input, O_RDONLY, 0)) < 0) {
perror("Couldn't open input file");
exit(0);
}
// dup2() copies content of fdo in input of preceeding file
dup2(fd0, 0); // STDIN_FILENO here can be replaced by 0
close(fd0); // necessary
}
//if '>' char was found in string inputted by user
if (out)
{
int fd1 ;
if ((fd1 = creat(output , 0644)) < 0) {
perror("Couldn't open the output file");
exit(0);
}
dup2(fd1, STDOUT_FILENO); // 1 here can be replaced by STDOUT_FILENO
close(fd1);
}
execvp(*argv, argv);
perror("execvp");
_exit(1);
// another syntax
/* if (!(execvp(*argv, argv) >= 0)) { // execute the command
printf("*** ERROR: exec failed\n");
exit(1);
*/
}
else if((pid) < 0)
{
printf("fork() failed!\n");
exit(1);
}
else { /* for the parent: */
while (!(wait(&status) == pid)) ; // good coding to avoid race_conditions(errors)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
50870 次 |
| 最近记录: |