【问题标题】:How to execute complex linux commands in Qt? [duplicate]如何在 Qt 中执行复杂的 linux 命令? [复制]
【发布时间】:2014-06-12 21:59:37
【问题描述】:

我想通过在 linux 中使用QProcess 运行命令来重新启动计算机。我已经在我的应用程序中硬编码了我的 root 密码。

当我在终端中运行以下命令时,它运行良好:

echo myPass | sudo -S shutdown -r now 

当我将命令放入 shell 脚本并通过QProcess 调用它时,它也是成功的:

QProcess process;
process.startDetached("/bin/sh", QStringList()<< "myScript.sh");

但是我不能通过直接传递给QProcess来运行它:

process.startDetached("echo myPass | sudo -S shutdown -r now ");

它只会打印myPass | sudo -S shutdown -r now

怎么可能直接使用QProcess来运行这么复杂的命令。 (不放入 shell 脚本)。

【问题讨论】:

    标签: c++ linux qt shell qprocess


    【解决方案1】:

    为此目的而存在的关键方法在QProcess中建立:

    void QProcess::setProcessChannelMode(ProcessChannelMode mode)

    void QProcess::setStandardOutputProcess(QProcess * destination)

    因此,以下代码 sn-p 将等同于 command1 | command2,而无需将自己限制为一种或另一种解释器:

    QProcess process1
    QProcess process2;
    
    process1.setStandardOutputProcess(&process2);
    
    process1.start("echo myPass");
    process2.start("sudo -S shutdown -r now");
    process2.setProcessChannelMode(QProcess::ForwardedChannels);
    
    // Wait for it to start
    if(!process1.waitForStarted())
        return 0;
    
    bool retval = false;
    QByteArray buffer;
    // To be fair: you only need to wait here for a bit with shutdown,
    // but I will still leave the rest here for a generic solution
    while ((retval = process2.waitForFinished()));
        buffer.append(process2.readAll());
    
    if (!retval) {
        qDebug() << "Process 2 error:" << process2.errorString();
        return 1;
    }
    

    您可以删除sudo -S 部分,因为您可以以root 身份运行这个小程序,并设置权限。您甚至可以为关机程序设置 setuid 或 setcap。

    在构建商业 Linux 系统时,我们通常会做一个最小的应用程序,该应用程序可以为其尝试执行的活动获取 setuid 或 setcap,然后我们在 Linux 上使用 system(3)QProcess 显式调用它。基本上,

    我会编写那个小应用程序以避免授予对整个应用程序的完全 root 访问权限,因此限制访问权限以防止恶意使用如下:

    sudo chmod u+s /path/to/my/application
    

    【讨论】:

    • 这很好用,我喜欢它,因为它更通用,更符合 Qt 方式。我不知道这是干什么用的:process2.setProcessChannelMode(QProcess::ForwardedChannels);
    • @Nejat:是的,如果没有它,它可能会起作用,但上次我在没有它时遇到了问题。它的目的是将子进程的输出重定向到主进程,所以,是的,这对于您的情况可能是不必要的。
    【解决方案2】:

    首先,您可以配置sudo 以避免询问您的密码。例如,成为sudo 组的成员并拥有该行

     %sudo  ALL=NOPASSWD:  ALL
    

    在您的/etc/sudoers 文件中。当然不询问密码会降低系统的安全性。

    要回答您关于 Qt 的问题,请记住 bash(1) 与所有 Posix 外壳一样,因此 /bin/sh,接受带有字符串的 -c 参数(实际上 system(3) 是分叉 /bin/sh -c)。所以只需执行

     process.startDetached("/bin/sh", QStringList()<< "-c" 
                           << "echo myPass | sudo -S shutdown -r now");
    

    作为AntiClimacus answered,将您的根密码放入可执行文件中是个坏主意。

    【讨论】:

    • 这是一个次优的想法,因为 Qt 对此有专门的 API,不会限制您使用解释器。
    • 另外,看来OP已经试过了,还问How is it possible to run such relatively complex commands directly using QProcess. (Not putting in a shell script).
    【解决方案3】:

    您必须将命令放入 shell 脚本并使用 QProcess 以您的 shell 脚本作为参数执行 shbash,因为您的命令包含 |必须shbash

    但是,这只是我的意见,但是:我认为这不是一个很好的解决方案来做你正在做的事情,即将你的 root 密码包含在一个可执行文件中。

    【讨论】:

    • 不推荐这样做,因为它限制了给定解释器的可用性。
    • 如果您阅读了问题,我已经尝试过成功。
    • @LaszloPapp:你知道没有 /bin/sh 的 Linux 系统吗?问题是关于 Linux,而不是所有操作系统。如果命令更复杂,有多个管道/重定向器,你会怎么做? 10 质量流程?将命令专用于 shell 脚本也更加灵活:如果您想更改命令,则无需再次编译可执行文件。
    • OP 明确地尝试过这个并询问:How is it possible to run such relatively complex commands directly using QProcess. (Not putting in a shell script). -> 你没有试图回答这个问题。此外,你也很困惑:解释器是不是 sh,而是bash。而且,是的,整个嵌入式行业都是基于busybox 或没有bash 的toybox。许多人还在桌面上使用 zsh 而不是 bash 等等。 OP想避免它并找到一个交叉解决方案。我仍然认为您只是在重申 OP 所写的内容,所以这不是试图回答这个问题。
    • 我并不感到困惑:sh 不是 bash,并不总是 bash 的符号链接,sh 是一个完整且独立的 shell (en.wikipedia.org/wiki/Bourne_shell)。甚至没有 bash 也没有 sh,例如如果您使用 zsh、dash 或其他 shell,那么在这种情况下,sh 指向正确的解释器。
    猜你喜欢
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    相关资源
    最近更新 更多