QProcess执行linux命令行的命令(详解各种情况可能存在的问题)

前言

因为我是做的linux下开发,所以程序中需要多次在qt中调用linux命令行的命令,并且需要根据命令的执行结果做出相应的判断。qt中使用QProcess类实现进程间通信,也就是说QProcess可以调用外部程序并获取外部程序的信息。linux中通过启动bash(windows中启动cmd)来执行命令行的命令,并可以获取命令行的返回信息。


下面我详细介绍一下QProcess的具体用法和我踩过的坑以及注意事项:

QProcess的重要方法:

start();                     //启动一个进程
close();                      //关闭启动的外部进程
write();                     //向外部进程写入数据
readAllStandardOutput();     //读取外部进程的标准输出
readAllStandardError();      //读取外部进程的错误信息
waitForStarted()			 //启动阻塞,等待程序启动完毕,期间整个程序所有进程阻塞
waitForFinished()			 //结束阻塞,等待程序结束完毕,期间整个程序所有进程阻塞

注意:QProcess中start()和write()中写的命令,末尾要加上\n(linux直接加\n,windows好像是\r\n,意思就是加个换行符),否则命令可能无法执行!!!


基础使用方法:

执行单条命令,且需要读取命令行返回信息时,代码如下:

	QProcess pro;
    connect(&pro,&QProcess::readyReadStandardOutput,this,[=,&pro]()mutable{ //注意我这里lambda表达式的写法,[]里的内容需要根据实际情况更改
  QString Output=pro.readAllStandardOutput();
    qDebug()<<"Output:"<<Output;
    });
    connect(&pro,&QProcess::readyReadStandardError,this,[=,&pro]()mutable{ 
        QString Error=pro.readAllStandardError();
        qDebug()<<"Error:"<<pro.readAllStandardError();
    });
pro.start("bash");			//在start中写命令,可将括号里的内容直接换成命令
    pro.waitForStarted();       //阻塞,等待bash启动完毕
	pro.waitForFinished();
	pro.close();				//在适当的位置关闭外部程序

优化

上面的代码是网上普遍给的使用方式,直接在start方法中写命令方便好用。但如果我想同时执行多条命令,且读出每次执行完命令的返回结果,这是一个QProcess对象就只能start一次。所以就必须把命令写在write()方法中,优化后的代码如下

QProcess pro;
    connect(&pro,&QProcess::readyReadStandardOutput,this,[=,&pro]()mutable{ //注意我这里lambda表达式的写法,[]里的内容需要根据实际情况更改
        QString Output=pro.readAllStandardOutput();
        qDebug()<<"Output:"<<Output;
    });
    connect(&pro,&QProcess::readyReadStandardError,this,[=,&pro]()mutable{ //注意我这里lambda表达式的写法,[]里的内容需要根据实际情况更改
        QString Error=pro.readAllStandardError();
        qDebug()<<"Error:"<<pro.readAllStandardError();
    });
pro.start("bash");
    pro.waitForStarted();       //阻塞,等待bash启动完毕
    pro.write("ls /root \n");
    delayMSec(200);     //非阻塞延迟给命令足够的执行时间,时间需根据命令的执行速度而定
QString path="/";
    QString ls_command=QString("ls %1\n").arg(path);    //执行带有变量的命令
    pro.write(ls_command.toLocal8Bit().data());
    delayMSec(200);
pro.close();				//在适当的位置关闭外部程序

非阻塞延迟delayMSec():–自己封装的

void MainWindow::delayMSec(unsigned int msec)
{
    QTime Time_set = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < Time_set )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

注意:write()方法不可与waitForFinished()一起使用,否则会阻塞30秒。waitForFinished()只能用start()一起使用


什么是阻塞?很重要!!!

我查了很多的资料,网上的博客基本都是把阻塞一笔带过,但我在执行复杂的调用linux命令时,发现阻塞才是决定程序能否正确执行的关键。

  • 阻塞:waitForStarted和waitForFinished,其实在执行外部命令时,也是需要花时间的,比如开启防火墙大概需要200ms,如果qt在执行开启防火墙操作,必须阻塞大概200ms,该命令才能执行成功,不然防火墙还没开启,qt就已经开始执行下一行代码了。读者可以尝试把waitForFinished加上和去掉对比一下
  • 非阻塞延迟delayMSec,这是我自己封装的方法,当写入多条命令时,如write1,write2…依然需要给每条命令执行的时间,我们所期望的是write1执行成功后再write2,write2成功后在执行后续的代码。但write和waitForFinished无法一起使用,所以只能自己添加延迟,但缺点是延迟的时间是手动设置的,无法确定延迟时间时,只能不断测试时间或者设置较长的时间
  • waitForFinished和非阻塞延迟区别:waitForFinished阻塞的时候,程序对外表现的时卡顿,程序中的所有线程都被阻塞掉了。比如我们想在阻塞的时候设置一个正在加载的动画提示,waitForFinished会导致动画不运行或者动画卡顿。我自己封装的非阻塞延迟delayMSec只会把程序执行的时间推迟,不会影响其他线程的运行。

我在阻塞上吃了很多亏,一遍一遍尝试代码,搜资料。


除了阻塞的地方是个坑外,qt中还无法识别管道“|”和重定向“>>”命令

解决方法:

	QProcess pro;
    pro.start("bash",QStringList() << "-c " << "ps -ef | grep firefox");       //执行带有管道的命令
    pro.waitForStarted();
    pro.waitForFinished();
    qDebug()<<"pro.readAll:"<<pro.readAll();
pro.close();				//在适当的位置关闭外部程序

2022.8.8更新

pro.start("bash",QStringList() << "-c" << "ps -ef | grep firefox");       //执行带有管道的命令

注意:-c小写且前后没有空格,我之前的写法错了,导致一直无法运行,特此更新,注意注意!


原理是使用start的这个方法。意思是先打开一个程序,然后将字符数组的命令写到程序中,但不知道为什么要先加个-c,因为这里的命令是直接写到bash终端里的,所以末尾应该不用加\n

image-20220519150535373


取代QProcess的方法-syetem()方法

system()是linux的方法,使用起来比QProcess更方便,但无法获取命令行的返回值。这里有个致命的问题就是有的命令有没有执行成功是必须要看命令行打印的信息的,system只能返回一个int数值,一般来说返回值为0说明该条命令执行完毕了,但无法确定有没有执行成功

	system("ls");
	system("systemctl start firewalld.service");		//这里可以写任意数量的命令

注意:system()也是阻塞命令,会等到命令执行完毕才会结束阻塞


但如果我们既需要执行多条命令,又要程序的返回信息,且又想让程序阻塞时间达到最小,可以将命令都写在shell脚本里,然后调用脚本,这样只需一次start,阻塞的问题也能解决

qt代码:

    QProcess pro;
    connect(&pro,&QProcess::readyReadStandardOutput,this,[=,&pro]()mutable{ //注意我这里lambda表达式的写法,[]里的内容需要根据实际情况更改
        QString Output=pro.readAllStandardOutput();
        qDebug()<<"Output:"<<Output;
    });
    connect(&pro,&QProcess::readyReadStandardError,this,[=,&pro]()mutable{ 
        QString Error=pro.readAllStandardError();
        qDebug()<<"Error:"<<pro.readAllStandardError();
    });
QString dirpath= QCoreApplication::applicationDirPath();        //----获取可执行文件所在的目录
    QString shell=QString(dirpath+"/test.sh %1 %2 %3\n").arg("/","/root","/home");	//解决传参问题
    pro.start(shell);			//执行脚本
    pro.waitForStarted();       //阻塞,等待bash启动完毕
    pro.waitForFinished();
    pro.close();

脚本中代码:

#!/bin/sh
	path1=$1
	path2=$2
	path3=$3
	ls ${path1}
	ls ${path2}
	ls ${path3}

执行结果:

img
使用脚本时记得给脚本文件添加可执行权限

chmod 777 test.sh

注意:最后还是想说一下使用阻塞会导致界面产生卡顿。想要解决这个问题自然要使用多线程,将阻塞代码在其他线程中运行即可。

链接:qt中Qthread线程的使用以及安全关闭

码字不易,如果这篇博客对你有帮助,麻烦点赞收藏,非常感谢!有不对的地方

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: qprocess是一个python库,可以帮助你在python程序中执行linux命令使用方法如下: ``` from qprocess import qp #执行命令 output = qp.run("ls -l") #获取输出 print(output.stdout) ``` 这样就可以在python程序中执行linux命令了。 ### 回答2: qprocess是一个Qt框架中的类,它提供了一种在Linux系统中执行命令的方式。使用qprocess需要先创建一个QProcess对象,并在对象中设置要执行命令和参数。然后调用QProcess对象的start方法来启动命令使用waitForStarted方法来等待进程启动完成,使用waitForFinished方法来等待进程执行完毕。在进程执行过程中,可以使用readAllStandardOutput和readAllStandardError方法来获取进程的标准输出和标准错误输出。下面是一个示例代码: ``` #include <QCoreApplication> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QProcess process; process.start("/bin/ls", QStringList() << "-l" << "-a"); // 执行ls -l -a命令 process.waitForStarted(); process.waitForFinished(); QByteArray output = process.readAllStandardOutput(); // 获取进程的标准输出 QByteArray error = process.readAllStandardError(); // 获取进程的标准错误输出 QString strOutput(output); QString strError(error); qDebug() << "Output:" << strOutput; qDebug() << "Error:" << strError; return a.exec(); } ``` 在上面的代码中,我们使用QProcess对象执行了ls命令,并且设置了参数-l和-a。然后我们使用waitForStarted方法等待进程启动完成,使用waitForFinished方法等待进程执行完毕。最后使用readAllStandardOutput和readAllStandardError方法获取进程的标准输出和标准错误输出,分别存储在output和error中。最后我们将这两个结果输出到控制台。注意,输出结果的形式为字节数组,我们需要先将其转换成QString格式后再输出。 总之,使用qprocess执行Linux命令非常方便,只需要简单的几行代码就可以完成大部分的需求。 ### 回答3: QProcess是一个Qt类,用于在应用程序中执行系统命令和应用程序。在Linux中,QProcess可以被用于执行任何可以在终端中执行命令,例如在终端中执行ls、mkdir、rm、cat等命令QProcess类提供了一个start方法,该方法用于启动一个新的进程来执行命令或应用程序。在start方法中,需要传递要执行命令及其参数,例如: ```C++ QProcess process; process.start("ls", QStringList() << "-l" << "/path/to/directory"); ``` 以上代码中,我们创建了一个QProcess对象,然后调用start方法来执行ls命令。在此方法中,我们需要传递两个参数,第一个参数是要执行命令,第二个参数是该命令的参数。在本例中,我们通过QStringList对象设置了ls命令的参数-l和要列出内容的目标目录。 在执行命令之后,QProcess提供了一些方法来读取命令输出的数据,例如: - readAllStandardOutput:读取命令输出的标准输出。 - readAllStandardError:读取命令输出的标准错误。 - waitForFinished:等待命令执行完毕。 例如,以下代码演示了如何执行ls命令并读取标准输出: ```C++ QProcess process; process.start("ls", QStringList() << "-l" << "/path/to/directory"); process.waitForFinished(); QString output = process.readAllStandardOutput(); qDebug() << output; ``` 以上代码中,我们使用了waitForFinished方法来等待ls命令执行完毕,然后使用readAllStandardOutput方法读取了标准输出,并将其输出到调试窗口中。 总之,QProcess可以被用于在Linux执行任何可以在终端中执行命令,并提供了一些方法来读取命令输出的数据。开发人员可以使用QProcess来集成系统命令和应用程序,以增强他们的应用程序功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值