C语言调用system执行SFTP命令输出未屏蔽、错误状态无法识别问题
问题原因及解决方案
问题1:重定向stdout/stderr后仍有终端输出
原因
OpenSSH的sftp工具默认运行在交互模式下,连接提示、命令提示符、传输状态等信息会直接写入当前进程关联的终端设备/dev/tty,不属于标准输出(stdout,文件描述符1)和标准错误(stderr,文件描述符2),因此对1和2的重定向无法拦截这类输出。
解决方法
修改sftp启动参数,关闭交互模式、开启静音模式:
- 新增
-q参数:启用静音模式,抑制连接提示、传输状态等非必要输出 - 新增
-b -参数:指定从标准输入读取批处理命令,完全关闭交互逻辑,不再向/dev/tty写入内容 - 可选新增
-o BatchMode=yes参数:禁用交互式密码输入,避免网络异常或认证失败时进程卡住
修改后的完整命令为:
echo "put /home/file1.txt /home/file2.txt" | sftp -q -F /dev/null -P 22022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o BatchMode=yes -b - admin@10.113.21.89 > /dev/null 2>&1
问题2:传输失败无法识别错误返回
原因
存在两个问题共同导致:
- sftp交互模式下,单条命令执行失败不会触发整个sftp进程返回非0退出码,默认始终返回0
- 原有C代码的返回值判断逻辑完全错误:只要sftp进程正常退出(无论执行成功还是失败),就直接返回-1;反而进程异常终止时才返回0,和预期逻辑完全相反。
解决方法
- 按问题1的方案修改sftp参数,启用批处理模式:批处理模式下任意命令执行失败,sftp进程就会返回非0的退出码
- 修正C代码的返回值判断逻辑:进程正常退出时,通过
WEXITSTATUS拿到的返回值为0代表传输成功,非0代表传输失败。
修改后的完整C代码如下:
#include <stdio.h> #include <stdlib.h> #include <sys/wait.h> int sftpFile() { char cmd[256] = "echo \"put /home/file1.txt /home/file2.txt\" | sftp -q -F /dev/null -P 22022 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o BatchMode=yes -b - admin@10.113.21.89 > /dev/null 2>&1"; int status = system(cmd); // system调用本身失败(无法启动shell) if (status == -1) { perror("system call failed"); return -1; } // sftp进程正常退出 if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); printf("sftp exit_code: %d\n", exit_code); // 退出码为0代表传输成功 if (exit_code == 0) { return 0; } else { return -1; } } // sftp进程异常终止(被信号杀死等) return -1; }
内容的提问来源于stack exchange,提问作者bvj0412
相关产品推荐
相关产品推荐

