【问题标题】:C++ shell command prompting for passwordC++ shell 命令提示输入密码
【发布时间】:2011-10-03 20:47:20
【问题描述】:

我正在尝试通过一个非常小的 C++ 程序调用一些 shell 命令。

“git clone”或“rsync”等需要密码的命令。 例如,由于 git 使用交互式 SSH,我无法为其提供密码。

到目前为止,我的程序如下:

#include <iostream>
#include <string>

std::string ExecuteShellCommand(const std::string& cmd) 
{  
  FILE* pipe = popen(cmd.c_str(), "r");

  if (!pipe) 
    return std::string("ERROR");

  char buffer[128];
  std::string result = "";

  while(!feof(pipe)) 
  {
    if(fgets(buffer, 128, pipe) != NULL)
      result += buffer;
  }

  pclose(pipe);
  return result;
}

int main()
{
  ExecuteShellCommand("git clone ssh://someurl/somerepo.git");
  return 0;
}

输出:

ssh_askpass: exec(/usr/libexec/ssh-askpass): 没有那个文件或目录

ssh_askpass: exec(/usr/libexec/ssh-askpass): 没有那个文件或目录

ssh_askpass: exec(/usr/libexec/ssh-askpass): 没有那个文件或目录

有没有办法让进程提示输入密码,就像我直接从命令提示符执行命令一样?

谢谢!

编辑: 理想情况下,我会直接在 Python 或 Shell 中执行此操作,但我的程序需要读取 C++ 中的不同结构(python 绑定有点矫枉过正)所以我为什么要尝试用 C++ 来做。

【问题讨论】:

  • 考虑使用 shell 的脚本语言,例如批处理和 sh。
  • @nightcracker:这是我的初衷,但请看我的编辑。

标签: c++ shell


【解决方案1】:

你有两个选择。

首先,对于那些拥有它的人,您可以使用每个程序的方法来解决这个问题。例如,git 具有 GIT_ASKPASSssh 具有基于密钥的身份验证。

其次,您可以使用pty 与这些程序进行通信。您可以使用expect 之类的程序或您自己的代码(请参阅posix_openpt 命令)来执行此操作。

【讨论】:

  • hummm 我现在正在查看 posix_openpt,我有点不清楚我应该如何使用文件描述符来打开新进程?
  • 在你 fork, dup 之后,从 pty 进入子节点的标准输入并关闭主节点。将密码写入主 pty。 pty 的行为有点像父母和孩子之间的pipe——除了它在孩子看来就像一个终端。 Python 有 pty.spawn and pty.fork 为您完成大部分工作。
  • 我真的建议你采纳 David 关于使用 expect 的建议,尤其是在这种情况下你应该看看 libexpect tcl.tk/man/expect5.31/libexpect.3.html。它将为您处理所有这些复杂问题,并为您提供与流程通信的简单 API。可能会出现许多您可能没有立即意识到的问题,例如 i/o 缓冲。 Expect 是解决所有这些问题的行之有效的解决方案。