【问题标题】:Get exit code of SFTP command run by system()获取 system() 运行的 SFTP 命令的退出代码
【发布时间】:2020-02-19 09:37:41
【问题描述】:

我的程序创建了一个使用expect 执行sftp 命令的脚本。该脚本应从 SFTP 服务器下载文件。生成脚本后,我的程序调用系统命令来运行脚本。遇到错误时脚本应该退出。例如,如果密码错误。我怎样才能得到 sftp 命令返回的错误?

以下是生成和运行脚本的代码:

downloadFileFromServer()
{
    ofstream downloadScript;
    string  result, command;

    downloadScript.open("/temp/download.sh");

    downloadScript << "#!/usr/bin/expect -f \n";
    downloadScript << "spawn sftp -P " + <port number> +
                      " " + <user name> +
                      "@" + <IP> + "\n";
    downloadScript << "expect { \ntimeout {\nsend_user \"Permission denied\\n\"\nexit\n}\n}\n";

    downloadScript << "send \"" + <password> + "\\n\"\n";
    downloadScript << "expect \"sftp>\"""\n";
    downloadScript << "send \"cd " + <source directory> + "\\n\"\n";
    downloadScript << "expect \"sftp>\"""\n";
    downloadScript << "send \"lcd " + <destination directory> + "\\n\"\n";
    downloadScript << "expect \"sftp>\"""\n";
    downloadScript << "send \"get " + <file name> + "\\n\"\n";
    downloadScript << "expect \"sftp>\"""\n";
    downloadScript << "send \"exit\\n\"\n";
    downloadScript << "expect -exact \"$\"""\n";

    downloadScript.close();

    command = "chmod +x /temp/download.sh && /temp/download.sh";
    system(command.c_str());

}

以下是创建的脚本:

#!/usr/bin/expect -f 
spawn sftp -P <port numner> <user name>@<IP>
expect "<user name>@<IP>'s password:"
expect { 
timeout {
send_user "Permission denied\n"
exit
}
}
send "<password>\n"
expect "sftp>"
send "cd <source directory>\n"
expect "sftp>"
send "lcd <destination directory>\n"
expect "sftp>"
send "get <file name>\n"
expect "sftp>"
send "exit\n"
expect -exact "$"

我希望我的程序捕获“权限被拒绝”错误。

【问题讨论】:

  • 您的脚本生成代码是用什么语言编写的?
  • 查看system(3)的手册了解如何获取退出码。
  • 你能在你的机器和 sftp 服务器之间设置 SSH 密钥吗?这会让你的生活变得更简单。
  • @ColinMacleod,我正在使用 C++

标签: c++ system expect


【解决方案1】:

所有进程在结束时都会设置一个数字退出代码 (0..255)。更改期望脚本,以便您可以区分正常结束的脚本(通常退出代码为 0)和错误后显式的 exit。通过向该行添加一个参数来执行此操作,例如:

...
send_user "Permission denied\n"
exit 77
...

您可以在 C/C++ 程序中恢复此代码

int wstatus = system(command.c_str());
if (WIFEXITED(wstatus))
  int exit_code = WEXITSTATUS(wstatus);

wstatus 由两部分组成,即进程的退出代码和一些标志,这些标志提供有关进程是否运行或被中断等信息。使用上述宏提取信息。 见man 3 exitman waitpid

【讨论】:

  • 我试图在“权限被拒绝”消息之后放置出口 1。当我得到 system() 返回的退出代码时,值是 256 而不是 1。这是为什么呢?
  • 我从其他文章中读到,为了得到退出代码,返回值必须除以256。所以如果我把退出77,返回值将是19712(除以256得到值 77)。
  • 你是对的。 system() 返回一个包含退出代码和其他信息的整数。您应该使用我添加到答案中的宏来提取您想要的值。
【解决方案2】:

您需要在检查超时之前发送密码

expect "<user name>@<IP>'s password:"
send "<password>\n"
expect {
    timeout {
        send_user "Permission denied\n"
        exit 1
    }
    "sftp>"
}
send "cd ..."

我希望寻找超时或提示,以先到者为准。

【讨论】:

  • 在尝试嵌入期望代码之前获取正确的代码。用expect -d 运行它,看看为什么模式不匹配。
  • 我从其他文章中读到,为了得到退出代码,返回值必须除以256。所以如果我把退出77,返回值将是19712(除以256得到值 77)。
  • 顺便问一下,为 cd 命令放置错误消息或退出循环的正确方法是什么?我试过了,但它没有退出:expect { send_user "No such file or directory\n" exit 2 "sftp>" }
  • 你不应该在那个位置有“send_user”:send "cd ...\r" 然后是expect { "No such file or directory" {exit 2} "sftp&gt;" } -- 酌情添加换行符
猜你喜欢
  • 2018-11-04
  • 2011-09-22
  • 2014-06-14
  • 1970-01-01
  • 2011-06-28
  • 2013-01-01
  • 2018-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多