【问题标题】:Getting all output from terminal in C从C中的终端获取所有输出
【发布时间】:2013-01-25 22:55:16
【问题描述】:

我目前正在开发一个 ssh 程序,我希望能够通过网络完全控制终端。我的问题是,如果我向服务器发送命令以在终端中运行,我如何获得终端打印的输出?我看过很多帖子说要使用popen() 命令,但从我尝试过的情况来看,我不能使用它来更改目录和执行其他命令,只能使用ls 等简单的东西。除了将其发送到command > filetoholdcommand 之类的文件之外,还有其他方法可以从终端获取输出吗?提前致谢!

【问题讨论】:

  • I am currently working on a ssh program - 你的意思是你在写一个 SSH 客户端?或者您是否使用现有的 SSH 客户端在远程机器上执行命令?第二个选项不会让您的登录会话保持打开状态,因此对于每个新连接,CWD 都会重置为您的 HOMEDIR。
  • @jweyrich 我正在编写客户端和服务器。你能澄清一下你说它不会让我的登录会话保持打开是什么意思吗?
  • 祝你顺利实现 SSH。
  • 我以SSH为例,基本上我只是向服务器发送命令,它会执行命令,然后从终端发回输出等。
  • @HurricaneChris:这可能是一项非常复杂的任务。您需要处理各种终端控制序列和模式。假设是 VT100 兼容终端,您可以在VT100 User Guide 中阅读更多内容。第 3 章包含许多关于模式、光标位置、滚动等的详细信息。但我希望这不会让您气馁。

标签: c linux terminal


【解决方案1】:

您想要“popen”功能。下面是运行命令ls /etc 并输出到控制台的示例。

#include #include int main(int argc, char *argv[]) { 文件 *fp; 整数状态; 字符路径[1035]; /* 打开命令进行读取。 */ fp = popen("/bin/ls /etc/", "r"); 如果(fp == NULL){ printf("运行命令失败\n"); 出口; } /* 一次读取一行输出 - 输出它。 */ 而(fgets(路径,sizeof(路径),fp)!= NULL){ printf("%s", 路径); } /* 关闭 */ 关闭(fp); 返回0; }

【讨论】:

  • 我知道如何使用popen() 以及如何发送ls 命令,但它无法更改目录或我尝试过的任何更有用的东西。
  • fgets(path, sizeof(path)-1, fp) 应该是 fgets(path, sizeof(path), fp) - stdlib 函数设计良好。
  • @HurricaneChris 您的错误可能与程序的 SSH 部分有关。
  • @syb0rg 我尝试使用类似于上述程序的程序,除了用用户的变量替换/bin/ls /etc/,在本例中为cd Documents/,它返回/bin/sh: Documents/: is a directory
  • Documents/ 在当前目录中吗?
【解决方案2】:

我会将此作为评论,但我没有足够的代表,因为我是新人。 cd 是一个内置的 shell 命令,所以你想使用 system()。但是 cd 对你的进程没有影响(你必须使用 chdir(),为此),所以你真正想要做的是通过 fork/exec 将 shell 作为子进程启动,将管道连接到它的 stdin 和 stdout,然后在用户会话或连接期间通过管道传输命令。

以下代码给出了总体思路。基本的,有缺陷的 - 使用 select() 而不是 usleep() 。

int argc2;
printf( "Server started - %d\n", getpid() );
char buf[1024] = {0};
int pid;
int pipe_fd_1[2];
int pipe_fd_2[2];
pipe( pipe_fd_1 );
pipe( pipe_fd_2 );

switch ( pid = fork() ) 
{
case -1:
    exit(1);
case 0: /* child */
    close(pipe_fd_1[1]);
    close(pipe_fd_2[0]);
    dup2( pipe_fd_1[0], STDIN_FILENO );
    dup2( pipe_fd_2[1], STDOUT_FILENO );
    execlp("/bin/bash", "bash", NULL);
default: /* parent */
    close(pipe_fd_1[0]);
    close(pipe_fd_2[1]);
    fcntl(pipe_fd_2[0], F_SETFL, fcntl(pipe_fd_2[0], F_GETFL, NULL ) | O_NONBLOCK );
    while(true)
    {
      int r = 0;
      printf( "Enter cmd:\n" );
      r = read( STDIN_FILENO, &buf, 1024 );
      if( r > 1 )
      {
        buf[r] = '\0';
        write(pipe_fd_1[1], &buf, r);
      }
      usleep(100000);
      while( ( r = read( pipe_fd_2[0], &buf, 1024 ) ) > 0 )
      {
        buf[r-1] = '\0';
        printf("%s", buf );
      }
      printf("\n");
    }
}

【讨论】:

  • 非常感谢您为我澄清了这一点,但是您将如何将 shell 作为子进程启动?
  • 查看编辑中添加的基本示例。当然应该放入带有适当标题的 main() 中,但无法粘贴整个 C 文件并使其正确格式化...
  • 非常感谢它完美运行!现在的问题是通过网络部分实现这一点。
猜你喜欢
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2020-09-07
  • 2013-09-06
  • 1970-01-01
  • 2013-08-18
  • 2019-01-06
相关资源
最近更新 更多