plink 、pscp非交互式自动执行相关命令

pscpplink 工具可以用于在Windows上以非交互式的方式进行自动化操作:

  • pscp :用于自动化的传输文件。
  • plink:用于在Windows上远程自动执行Linux命令。

1、batch 文件中执行Linux 命令

在一些场景下有些 Linux命令操作需要将其放在batch文件中,提供给用户进行一键式自动运行。在batch文件中内容如下:

batch 内容
@echo off
setlocal

set remoteHost=172.16.21.100
set username=Tom
set password=xod123
set linuxCommand="cd /home/Tom/x666 && ls"
set plinkPath="D:/Programs/plink.exe"

%plinkPath% -batch -ssh -l %username% -pw %password% %remoteHost% %linuxCommand%

【注意】:batch脚本中 set命令语法很严格, 变量的等号前后都不能有空格,否则会导致意外的错误,如:
set cmd = "ls" 后面的 %cmd%会无法取值,因为变量后的空格也会被识别为变量的一部分,即%cmd %导致变量无法展开,最终导致脚本无法有效执行。

以上参数说明:

  • 通过 set 设置相关变量的值,以便后续直接使用
  • plink.exe 程序直接通过 ssh 来进行远程执行Linux上的命令行:
    • -batch:可以用来取消出现交互信息,如Access granted. Press Return to begin session.。直接显示远程命令执行的结果。
    • -ssh :使用ssh协议
    • -l:login 表示远程Linux设备的用户名,后接用户名
    • -pw:表示密码信息,后面接用户密码。
    • 最后就是IP地址和需要执行的Linux命令

2、代码中 QProcess 直接远程执行Linux命令行,无batch文件

在Qt 中常见的方式是使用 QProcess 来启动这个进程,去执行远程的命令行,这个方式不通过启动 Batch文件,能够有效的避免了中文路径、空格导致的问题

Code
// 调用代码
    QString plinkPath = "D:/Programs/plink.exe";
    QString userName = "Tom";
    QString passWd = "xod123";
    QString host = "172.16.21.100";
    QString cmdRemote = "cd /home/Tom/x666 && ls"; 

    QString cmd = QString("\"%1\" -ssh -l %2 -pw %3 %4 \"%5\"").arg(plinkPath, userName, passWd, host, cmdRemote);

    QString outputMsg;
    bool ret = StartProcess(cmd, outputMsg, "UTF-8");

// 执行函数,参数cmd为命令行,QProcess 并不能解释脚本内容,它会把第一个参数(第一个空格前内容)当作启动程序
bool StartProcess(const QString& cmd, QString& outputMsg, std::string encode = "UTF-8")
{
    QProcess process;
    process.setProcessChannelMode(QProcess::SeparateChannels);
    process.start(cmd);

    // 需要判断进程是否成功启动
    if(!process.waitForStarted())
    {
        outputMsg = process.errorString();
        return false;
    }

    if (!process.waitForFinished(30000))
    {
        outputMsg = "Process timeout.";
        return false;
    }
    
    const QTextCodec* codec = QTextCodec::codecForName(encode.c_str());
    const QString outMsg = codec->toUnicode(process.readAllStandardOutput());
    const QString errMsg = codec->toUnicode(process.readAllStandardError());

    if (errMsg.trimmed().isEmpty())
    {
        outputMsg = outMsg;
        return true;
    }

    outputMsg = errMsg;
    return false;
}

【注意】:
在Linux上执行的命令行,一般是 UTF-8编码,而Windows上一般是gbk编码,所以如果是远程执行Linux上的命令行中有中文字符,需要将其转换成 UTF-8的编码格式才能正常显示,如果执行的 cmd 直接是Windows设备上的命令,则需要设置gbk的编码形式


二、pscp传输文件: pscp.exe [options] [source] [user]@[host]:[destination]

经常用于无需输入密码的自动化执行流程中,执行指令如下:

  • pscp -i [C:\private_key.ppk] [file1.txt] user@remote_host:/home/user/ :使用密匙自动化传输文件。
  • pscp -pw [123456] [file1.txt file2.txt] user@remote_host:/home/user/:使用明文密码的形式进行传输文件,多个文件时,并列在一起

1、以batch脚本的形式进行执行传输

batch
@echo off
setlocal

set pscpPath="D:/pscp.exe"
set password=x012345
set srcFiles="D:/Tmp/file1.txt" "D:/Tmp/Test Files/config.ini" "D:/Tmp/tmp.png"
set userName=ad
set host=172.16.20.196
set destPath="/home/hut/x01"

%pscpPath% -pw %password% %srcFiles% %userName%@%host%:%destPath%

endlocal

以上的内容存放在batch文件中,可以提供给用户来直接运行batch文件。


三、QProcess 启动batch脚本

通过QProcess直接运行batch脚本需要注意路径中的特殊字符等问题,以下为完整的实现接口:

#include <QProcess>
#include <QDir>
#include <QTextCodec>
#include <QFileInfo>
#include <QDebug>

/**
 * @brief 执行指定的 Batch 脚本(支持中文路径和空格路径)
 * @param batchPath Batch文件的完整路径
 * @param outputInfo [输出] 执行过程中的标准输出和错误输出
 * @return bool 执行成功返回 true,失败返回 false
 */
bool ExecuteBatch(const QString& batchPath, QString & outputInfo)
{
    outputInfo.clear();

    // 1. 基础检查:判断文件是否存在
    if (!QFileInfo::exists(batchPath)) {
        outputInfo = QString("Error: File not found: %1").arg(batchPath);
        return false;
    }

    // 2. 路径转换:将路径转换为 Windows 原生格式 (将 / 替换为 \ )
    // 虽然 Qt 支持 /,但在调用 cmd.exe 时,原生反斜杠最稳健
    QString nativePath = QDir::toNativeSeparators(batchPath);

    QProcess process;
    process.setProcessChannelMode(QProcess::MergedChannels); // 将标准输出和标准错误合并,方便查看所有日志

    // 3. 核心修正:使用 cmd.exe /c 来运行
    // QProcess 的参数列表机制会自动处理路径中的空格,自动添加引号,无需手动拼接 "\""
    QString program = "cmd.exe";
    QStringList arguments;
    arguments << "/c" << nativePath;

    // 4. 启动进程
    process.start(program, arguments);

    // 5. 等待启动
    if (!process.waitForStarted()) {
        outputInfo = QString("Error: Failed to start cmd.exe. %1").arg(process.errorString());
        return false;
    }

    // 6. 等待结束 (这里设置超时时间为 30000ms,即30秒,可视情况调整,-1表示无限等待)
    // 如果脚本执行时间较长,建议增加此值或设为 -1
    if (!process.waitForFinished(30000)) {
        outputInfo = "Error: Process operation timed out.";
        process.kill(); // 超时则杀死进程
        return false;
    }

    // 7. 获取输出内容并处理编码
    // cmd.exe 在中文 Windows 下默认输出是 GBK 编码
    // 如果不转换,获取到的中文(如“系统找不到指定路径”)会是乱码
    QByteArray rawOutput = process.readAll();
    
    // 尝试使用系统本地编码解码 (通常是 GBK)
    // 如果你的 batch 脚本内部显式调用了 chcp 65001,则这里可能需要改用 UTF-8
    QTextCodec *codec = QTextCodec::codecForLocale(); 
    if (codec) {
        outputInfo = codec->toUnicode(rawOutput);
    } else {
        outputInfo = QString::fromLocal8Bit(rawOutput);
    }

    // 8. 判断执行结果
    // exitCode == 0 通常表示执行成功
    if (process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0) {
        return true;
    } else {
        outputInfo += QString(" Process failed with exit code: %1").arg(process.exitCode());
        return false;
    }
}
posted @ 2025-06-27 09:06  Jeffxue  阅读(277)  评论(0)    收藏  举报