如何用libssh的C程序在Linux/Unix免路径运行$HOME/[.local/]bin程序
如何通过libssh无需指定路径运行用户目录下的程序?
问题背景
需要在无root权限的类Unix远程节点上,通过libssh的C程序运行安装在$HOME/.local/bin或$HOME/bin路径下的程序,效果等同于执行命令:
ssh user01@192.168.1.2 $SHELL -l -c "foo &"
当前已能通过指定路径实现:
rc = ssh_channel_request_exec(channel, "cd /home/user01/.local/bin/; ./foo &");
但希望直接用rc = ssh_channel_request_exec(channel, "foo &");实现,是否可行?需要哪些操作?
可行方案
这是可行的,核心是让远程shell加载用户的PATH配置,以下是具体实现方式:
1. 启动登录shell执行命令
libssh默认通过ssh_channel_request_exec启动的是非登录shell,不会加载用户的登录配置文件(如~/.bash_profile、~/.profile),而这些文件通常会把$HOME/.local/bin和$HOME/bin加入PATH。
要模拟ssh命令的$SHELL -l -c行为,只需将exec的命令改为:
rc = ssh_channel_request_exec(channel, "$SHELL -l -c 'foo &'");
$SHELL会自动使用远程用户的默认shell-l参数让shell以登录模式启动,加载用户的PATH配置-c用于指定要执行的命令foo &
如果明确知道远程shell是bash,也可以直接写:
rc = ssh_channel_request_exec(channel, "/bin/bash -l -c 'foo &'");
2. 手动指定PATH后执行命令
如果不想依赖登录shell的配置,也可以在命令中直接导出包含目标路径的PATH:
rc = ssh_channel_request_exec(channel, "export PATH=$HOME/.local/bin:$HOME/bin:$PATH; foo &");
这种方式直接临时扩展PATH,确保系统能找到foo命令。
3. 确认远程配置正确性
确保远程用户的登录配置文件中确实添加了对应路径,比如:
- 对于bash,检查
~/.bash_profile或~/.profile是否有类似行:export PATH="$HOME/.local/bin:$HOME/bin:$PATH" - 对于zsh,检查
~/.zprofile或~/.zshrc
修改后的示例代码
将原代码中的执行命令行替换为上述方案之一即可,比如用登录shell的版本:
#include <libssh/libssh.h> #include <stdlib.h> #include <stdio.h> void free_channel(ssh_channel channel) { ssh_channel_send_eof(channel); ssh_channel_close(channel); ssh_channel_free(channel); } void free_session(ssh_session session) { ssh_disconnect(session); ssh_free(session); } void error(ssh_session session) { fprintf(stderr, "Error: %s\n", ssh_get_error(session)); free_session(session); exit(-1); } int main() { ssh_session session; ssh_channel channel; int rc, port = 22; char buffer[1024]; unsigned int nbytes; printf("Session...\n"); session = ssh_new(); if (session == NULL) exit(-1); ssh_options_set(session, SSH_OPTIONS_HOST, "192.168.1.2"); ssh_options_set(session, SSH_OPTIONS_PORT, &port); ssh_options_set(session, SSH_OPTIONS_USER, "user01"); printf("Connecting...\n"); rc = ssh_connect(session); if (rc != SSH_OK) error(session); printf("Publickey Autentication...\n"); rc = ssh_userauth_publickey_auto(session, NULL, NULL); if (rc != SSH_AUTH_SUCCESS) error(session); printf("Channel...\n"); channel = ssh_channel_new(session); if (channel == NULL) exit(-1); printf("Opening...\n"); rc = ssh_channel_open_session(channel); if (rc != SSH_OK) error(session); printf("Executing remote command...\n"); // 使用登录shell执行foo命令 rc = ssh_channel_request_exec(channel, "$SHELL -l -c 'foo &'"); if (rc != SSH_OK) error(session); printf("Received:\n"); nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); while (nbytes > 0) { fwrite(buffer, 1, nbytes, stdout); nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0); } free_channel(channel); free_session(session); return 0; }
注意事项
- 无意义的代码替换(比如重复写
ssh_channel_write)无法解决问题,需聚焦于shell启动模式或PATH设置。 - 如果
foo是后台运行程序,可搭配nohup避免会话结束后程序被终止:rc = ssh_channel_request_exec(channel, "$SHELL -l -c 'nohup foo &'");
内容的提问来源于stack exchange,提问作者Denilson Souza Bêlo
相关产品推荐
相关产品推荐

