Linux Shell 的小问题 (高分请教达人)

threeleafzerg007 2009-08-04 04:46:12
代码逻辑是:自己先pipe建立管道 然后fork一个子进程 把子进程的输入输出重定向到 pipe2端 然后就 execl("/bin/sh" "sh" (char*)0) 最后主进程通过获取自己的输入 然后通过管道传至子进程 子进程因为是bash 然后执行命令 把结果通过 通过管道返回给 主进程

遗憾的是只有第一次执行命令是正确的 然后就一直显示所输入的东西 并且第一次输入时间如果很长 它依然会显示所输入的东西 原因何在,请教高手?


#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/select.h>
#include <errno.h>


int fds[2];

void do_shell();
void do_ioredirect();
void sig_chld(int signo)
{
printf("receive a SIGCHLD\n");
return;
}

int main(int argc,char **argv)
{
char buf[256];
int maxfd,nread;

signal(SIGCHLD,sig_chld);

if(pipe(fds) < 0)
{
perror("pipe");
exit(-1);
}

do_shell();

for(;;)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(0,&rset);
FD_SET(fds[0],&rset);
maxfd = fds[0] + 1;
memset(buf,0x00,sizeof(buf));

int n = select(maxfd,&rset,NULL,NULL,NULL);
if( -1 == n && errno == EINTR)
continue;
else if(-1 == n)
{
perror("select");
exit(-1);
}
if(FD_ISSET(0,&rset))
{
nread = read(0,buf,256);
write(fds[1],buf,nread);
}
if(FD_ISSET(fds[0],&rset))
{
nread = read(fds[0],buf,256);
printf("%s",buf);
}

}
return 0;
}

void do_shell()
{
int pid;

switch((pid = fork()))
{
case -1:
perror("fork");
exit(-1) ;
case 0:
do_ioredirect();
if(execl("/bin/bash","sh",(char *)0) < 0)
{
perror("execl");
exit(-1);
}
default:
break;
}
return;
}

void do_ioredirect()
{
if(dup2(fds[0],STDIN_FILENO) < 0)
{
perror("fd[0] dup2");
exit(-1);
}

if(dup2(fds[1],STDOUT_FILENO) < 0)
{
perror("fd[1] dup2");
exit(-1);
}
}


...全文
195 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
threeleafzerg007 2009-08-05
  • 打赏
  • 举报
回复
我已经找到原因了 呵呵 因为 /bin/sh 执行的时候用了 -i 所以即使被重定向依然会 读终端 所以会有信号

system 肯定是不行的了 popen还靠点谱 但是为了每次执行一个shell 命令而 起一个进程 关一个进程 代价实在太大了!
steptodream 2009-08-05
  • 打赏
  • 举报
回复
友情UP!
sunnyqboy 2009-08-04
  • 打赏
  • 举报
回复
用system直接执行结果,传给进程不行么?楼主使用父子进程传值,是为了增加并行性?
blackbillow 2009-08-04
  • 打赏
  • 举报
回复
On POSIX-compliant platforms, SIGTTIN is the signal sent to a process when it attempts to read from the tty while in the background.
threeleafzerg007 2009-08-04
  • 打赏
  • 举报
回复
在我写了如下代码

void sig_ttin(int signo)
{
printf("receive a SIGTTIN");
return ;
}

signal(SIGTTIN,sig_ttin);

终端就不停的打印出 sig_ttin的字符串,显然我的主进程不断的收到SIGTTIN 想问一下这是为何?有没有人能解释哈?
threeleafzerg007 2009-08-04
  • 打赏
  • 举报
回复
另一种ps

charlesye@charlesye-desktop:~/Program/salira_shell$ ps -ely | grep test
T 1000 5917 5266 0 80 0 720 696 signal pts/0 00:00:00 test
T 1000 6054 5266 0 80 0 724 696 signal pts/0 00:00:00 test

应该是被信号停止了, 想问一下是何种信号(明天我会写代码捕捉) 为何会产生信号?
threeleafzerg007 2009-08-04
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 blackbillow 的回复:]
管道应该是单向的,但这里你拿来双向传输数据会出问题的
[/Quote]

你说到点子上了

修改代码如下:

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/select.h>
#include <errno.h>


int fds1[2];
int fds2[2];

void do_shell();
void do_ioredirect();
void sig_chld(int signo)
{
printf("receive a SIGCHLD\n");
return;
}

int main(int argc,char **argv)
{
char buf[256];
int maxfd,nread;

signal(SIGCHLD,sig_chld);

if(pipe(fds1) < 0)
{
perror("pipe");
exit(-1);
}

if(pipe(fds2) < 0)
{
perror("pipe");
exit(-1);
}


do_shell();
for(;;)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(0,&rset);
FD_SET(fds2[0],&rset);
maxfd = fds2[0] + 1;
memset(buf,0x00,sizeof(buf));

int n = select(maxfd,&rset,NULL,NULL,NULL);
if( -1 == n && errno == EINTR)
continue;
else if(-1 == n)
{
perror("select");
exit(-1);
}
if(FD_ISSET(0,&rset))
{
nread = read(0,buf,256);
write(fds1[1],buf,nread);
}
if(FD_ISSET(fds2[0],&rset))
{
nread = read(fds2[0],buf,256);
printf("%s",buf);
}

}
return 0;
}

void do_shell()
{
int pid;

switch((pid = fork()))
{
case -1:
perror("fork");
exit(-1) ;
case 0:
do_ioredirect();
if(execl("/bin/sh","/bin/sh","-i",(char *)0) < 0)
{
perror("execl");
exit(-1);
}
default:
close(fds1[0]);
close(fds2[1]);
break;
}
return;
}

void do_ioredirect()
{

if(dup2(fds1[0],STDIN_FILENO) < 0)
{
perror("fd[0] dup2");
exit(-1);
}

if(dup2(fds2[1],STDOUT_FILENO) < 0)
{
perror("fd[1] dup2");
exit(-1);
}
close(fds1[1]);
close(fds2[0]);
}



基本工作正常 不过出现新问题:

进程在执行几个命令后会发生:

charlesye@charlesye-desktop:~/Program/salira_shell$ ./test
$ who
charlesye tty7 Aug 4 19:46 (:0)
charlesye pts/0 Aug 4 19:46 (192.168.108.1)
$ ls

[3]+ Stopped ./test



进程状态是:


charlesye@charlesye-desktop:~/Program/salira_shell$ ps aux | grep test
1000 5626 0.0 0.1 2784 724 pts/0 T 20:01 0:00 ./test
1000 5648 0.0 0.1 2784 724 pts/0 T 20:08 0:00 ./test
1000 5682 0.0 0.1 2784 724 pts/0 T 20:09 0:00 ./test
1000 5691 0.0 0.1 2020 568 pts/0 S+ 20:10 0:00 grep test



有人知道为啥它会被停止不?
yhf365 2009-08-04
  • 打赏
  • 举报
回复
进来学习一下
blackbillow 2009-08-04
  • 打赏
  • 举报
回复
void do_ioredirect()
{
if(dup2(fds[0],STDIN_FILENO) < 0)
{
perror("fd[0] dup2");
exit(-1);
}
/* 注释掉这一段就没问题了
if(dup2(fds[1],STDOUT_FILENO) < 0)
{
perror("fd[1] dup2");
exit(-1);
}
*/
}
blackbillow 2009-08-04
  • 打赏
  • 举报
回复
管道应该是单向的,但这里你拿来双向传输数据会出问题的
ShowMan 2009-08-04
  • 打赏
  • 举报
回复
兄弟技术挺好,写的不错,mark一下。
晚上好好看看。
Jagen在路上 2009-08-04
  • 打赏
  • 举报
回复
你的shell脚本怎么写的?

23,116

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧