Linux下Qt启、停“.sh”脚本文件及获取终端打印信息

本文介绍了在Qt应用程序中执行Shell命令的方法,包括弹出新终端执行特定指令、关闭指定名称的进程以及从终端捕获输出信息的具体实现细节。

1、弹出新终端并执行指令

char* ch0;
QString pinip0 = "gnome-terminal -x bash -c \"/home/qt/Server/opengadgetron.sh\"";
qDebug()<<pinip0;
QByteArray ba0 = pinip0.toLatin1();
ch0=ba0.data();
int ret0 = system(ch0);
qDebug()<<ret0;

2、关闭相应名称进程

char* ch0;
QString pinip0 = "killall gadgetron";
qDebug()<<pinip0;
QByteArray ba0 = pinip0.toLatin1();
ch0=ba0.data();
int ret0 = system(ch0);
qDebug()<<ret0;

3、获取终端打印信息内容

QString str = "killall gadgetron";
FILE* fp = popen(str.toLocal8Bit().data(), "r");
if(nullptr != fp){
		char buf[1024] = {0};
		char result[2000] = {0};
		while(fgets(buf, sizeof(buf), fp)){
				strcat(result, buf);
				if(strlen(result) > sizeof(buf)){
					break;
				}
		}
QString resultStr = QString("%1").arg(result);
printf("%s\n",resultStr.toLocal8Bit().data());
pclose(fp);
fp=nullptr;
}
<think> 我们计划在Ubuntu系统中通过QProcess运行一个.sh脚本来实现Qt应用程序的重。具体步骤包括: 1. 编写一个负责重shell脚本 2.Qt应用程序中通过QProcess动该脚本 需要注意的是,在Ubuntu中,图形界面程序通常需要知道显示服务器(如X11或Wayland)的环境变量,特别是DISPLAY和XAUTHORITY等。因此,在脚本中可能需要设置环境变量。 步骤: 1. 创建重脚本(例如restart_app.sh): 该脚本需要: - 杀死当前正在运行的Qt应用程序进程(如果有) - 重新Qt应用程序 2.Qt应用程序中,当需要重时,动这个脚本。 但是,要注意:如果当前应用程序正在运行,然后动一个脚本来杀死自己,可能会导致不可预知的行为。因此,我们通常的做法是: - 动一个外部程序(脚本)来等待当前程序退出,然后再重新动。 具体实现: 首先,编写重脚本(restart_app.sh): #!/bin/bash # 等待当前进程退出(如果有必要的话,可以设置一个超时) # 然后动应用程序 # 假设应用程序名为my_qt_app,位于当前目录下,或者已经安装在系统路径中 # 如果已经知道进程名,可以使用pkill或者killall,但要注意避免误杀 # 方法:我们可以让脚本接收两个参数:要杀死的进程名和要动的程序路径 if [ $# -lt 2 ]; then echo "Usage: $0 <process_name> <app_path>" exit 1 fi PROCESS_NAME=$1 APP_PATH=$2 # 尝试杀死进程 pkill -9 "$PROCESS_NAME" # 等待一段时间,确保进程已经结束 sleep 1 # 动程序 # 注意:如果程序需要特定的环境变量,这里可能需要设置 nohup "$APP_PATH" >/dev/null 2>&1 & 然后,在Qt应用程序中,当需要重时,这样调用: void restartApplication() { QString program = "/bin/bash"; QStringList arguments; arguments << "/path/to/restart_app.sh" << "my_qt_app" // 进程名 << "/path/to/my_qt_app"; // 可执行文件路径 QProcess::startDetached(program, arguments); // 退出当前程序 QCoreApplication::exit(0); } 但是,这里有一个问题:当我们脚本的时候,脚本会立即尝试杀死当前进程,而当前进程可能还没有退出。所以我们需要让脚本等待当前进程退出后再动新实例。然而,上面的脚本在杀死进程后立即动,可能当前进程还没有完全退出(特别是Qt应用需要一些时间清理资源)。我们使用sleep 1等待1秒,通常是足够的。 另一种更安全的方法是:在退出当前应用程序后再动新实例,而不需要杀死进程。我们可以这样做: restart_app.sh: #!/bin/bash # 等待进程退出(通过进程名判断),然后动 PROCESS_NAME=$1 APP_PATH=$2 # 先尝试杀死进程,但也可以不杀,因为我们会在脚本中等待进程退出 # 这里我们改为等待进程退出 # 使用while循环检查进程是否还在运行 while pgrep -x "$PROCESS_NAME" > /dev/null; do sleep 0.1 done # 动程序 nohup "$APP_PATH" >/dev/null 2>&1 & 在Qt中这样调用: void restartApplication() { QString program = "/bin/bash"; QStringList arguments; arguments << "/path/to/restart_app.sh" << "my_qt_app" // 进程名 << "/path/to/my_qt_app"; // 可执行文件路径 QProcess::startDetached(program, arguments); // 退出当前程序,这样脚本就会检测到进程退出 QCoreApplication::exit(0); } 这样,脚本会一直等待当前进程退出,然后动新的实例。 注意事项: 1. 脚本需要可执行权限:chmod +x /path/to/restart_app.sh 2. 进程名必须是准确的,可以通过在终端运行`ps aux`查看。 3. 如果程序路径中包含空格或特殊字符,需要确保正确传递参数(使用引号)。 然而,我们也可以不通过脚本,直接在Qt中实现: - 使用QProcess动一个新进程,这个新进程会等待当前进程退出后再动应用程序。 但使用脚本可以更灵活,且便于修改。 另一种Qt内部的实现(不依赖脚本): void restartApplication() { QString program = QCoreApplication::applicationFilePath(); QStringList arguments = QCoreApplication::arguments(); QString workingDirectory = QCoreApplication::applicationDirPath(); // 创建一个新的进程,这个进程会等待当前进程结束再动 QProcess *restartProcess = new QProcess(); restartProcess->setProgram(program); restartProcess->setArguments(arguments); restartProcess->setWorkingDirectory(workingDirectory); QProcess::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [restartProcess]() { restartProcess->start(); }); // 退出当前程序 QCoreApplication::exit(0); } 但是这种方法在Windows下可行,在Linux下,当程序退出后,新动的程序可能会因为缺少显示环境变量(如DISPLAY)而无法动图形界面。因此,我们需要确保新进程继承了正确的环境。 实际上,我们可以使用QProcess::startDetached直接动新程序,然后在退出当前程序: void restartApplication() { QString program = QCoreApplication::applicationFilePath(); QStringList arguments = QCoreApplication::arguments(); QString workingDirectory = QCoreApplication::applicationDirPath(); // 动新程序 QProcess::startDetached(program, arguments, workingDirectory); // 退出当前程序 QCoreApplication::exit(0); } 这样简单的方法在大多数情况下是有效的。但是,有可能出现新程序动时旧程序还没有完全退出的情况,导致资源冲突(比如同一个端口被两个程序同时占用等)。为了避免这种情况,我们可以让新程序延迟动: // 在动新程序之前,让当前进程先退出,然后新进程再动。我们可以使用一个小技巧:动一个bash命令,先睡眠一小段时间,然后再动程序。 QProcess::startDetached("bash", {"-c", "sleep 1; /path/to/app"}); 因此,我们可以这样写: QProcess::startDetached("bash", {"-c", "sleep 1; \""+program+"\" " + arguments.join(" ") + " &"}); 但是要注意,如果路径中有空格,这样拼接可能会有问题。我们可以使用QProcess的另一种方式: QString command = QString("sleep 1; \"%1\" %2").arg(program).arg(arguments.join(" ")); QProcess::startDetached("bash", {"-c", command}); 但这种方法也要注意命令行参数中如果有特殊字符(如引号)可能会出错。 综上所述,使用脚本的方式更可靠,但是如果不希望使用外部脚本,可以在Qt内部通过bash命令延迟动。 我们提供一个在Qt内部实现的延迟重方法: void restartApplication() { QString program = QCoreApplication::applicationFilePath(); QStringList arguments = QCoreApplication::arguments(); QString workingDirectory = QCoreApplication::applicationDirPath(); // 构建命令行 QString command; command += "sleep 1; "; // 延迟1秒 command += "\"" + program + "\""; for (const QString& arg : arguments) { // 如果参数包含空格或特殊字符,需要转义 QString tmp = arg; tmp.replace("\"", "\\\""); // 转义双引号 command += " \"" + tmp + "\""; } command += " &"; // 后台运行 // 使用bash执行 QProcess::startDetached("bash", {"-c", command}); // 退出当前程序 QCoreApplication::exit(0); } 但是,更简单且推荐的方法是使用脚本,因为脚本可以处理更复杂的逻辑,并且避免了在代码中拼接命令字符串可能带来的问题。 因此,我们回到最初的方法:使用外部脚本,并采用等待进程退出的方式(而不是简单的sleep)。 最终方案: 步骤1:创建脚本 restart_app.sh (放在应用程序目录下,或者固定路径) #!/bin/bash # 参数1:进程名(用于等待进程退出) # 参数2:要动的程序路径 # 等待进程退出 while pgrep -x "$1" > /dev/null; do sleep 0.1 done # 动新程序 nohup "$2" >/dev/null 2>&1 & 步骤2:在Qt中调用脚本 void restartApplication() { QString scriptPath = "/path/to/restart_app.sh"; QString appName = QCoreApplication::applicationName(); // 注意:确保这个名称和进程名一致 QString appPath = QCoreApplication::applicationFilePath(); if (!QFile(scriptPath).exists()) { qWarning() << "Restart script not found!"; return; } // 脚本 QProcess::startDetached("/bin/bash", {scriptPath, appName, appPath}); qApp->exit(0); // 退出当前程序 } 注意:在Qt中,应用程序名称默认可能是可执行文件的名称(不包括路径),但可以通过`QCoreApplication::setApplicationName`设置。另外,使用`pgrep -x`时,进程名必须完全匹配(不包括路径)。因此,确保appName就是进程名(例如,如果可执行文件是myapp,那么进程名就是myapp)。 验证:可以通过在终端运行`ps aux | grep myapp`来查看进程名。 如果进程名是包含路径的,那么上面的脚本中pgrep需要去掉路径。所以,我们传递的appName应该只是可执行文件的基本名称。 例如: appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); 因此,在restartApplication函数中: QString appName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); 这样,就可以确保进程名正确。 最后,记得给脚本执行权限:`chmod +x /path/to/restart_app.sh` 总结:这种方法安全可靠,能够确保在程序完全退出后再动新实例。 </think> 以下是在 Ubuntu 中使用 `QProcess` 运行 `.sh` 脚本实现 Qt 应用程序重的完整解决方案: ### 解决方案步骤 #### 1. 创建重脚本 `restart_qt.sh` ```bash #!/bin/bash # 获取当前Qt进程ID QT_PID=$(pgrep -f "my_qt_app") # 替换为实际应用名 # 终止当前Qt进程 kill -15 $QT_PID 2>/dev/null && sleep 1 # 安全终止,等待1秒 # 强制终止残留进程 kill -9 $QT_PID 2>/dev/null # 重Qt应用 (根据实际路径修改) nohup /path/to/your/qt_app >/dev/null 2>&1 & ``` #### 2.Qt代码中调用脚本 ```cpp #include <QProcess> #include <QDebug> void restartQtApp() { QProcess *process = new QProcess(); // 设置工作目录(可选) process->setWorkingDirectory("/path/to/script"); // 脚本 (两种方式任选) // 方式1:直接调用bash执行 process->start("bash", QStringList() << "/path/to/restart_qt.sh"); // 方式2:通过system调用 // system("bash /path/to/restart_qt.sh &"); // 检查执行状态 if (!process->waitForStarted(3000)) { qDebug() << "脚本失败:" << process->errorString(); } // 可选:程序自退出 QCoreApplication::exit(0); } ``` ### 关键注意事项 1. **脚本权限配置**: ```bash chmod +x /path/to/restart_qt.sh ``` 2. **进程名匹配**: - 替换 `my_qt_app` 为实际进程名(可通过 `ps aux | grep your_app` 确认) - 或使用 `pkill -f "executable_name"` 替代 `pgrep` 3. **环境变量问题**: ```cpp // 确保继承环境变量(特别是DISPLAY) QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("DISPLAY", ":0"); // X11显示服务器 process->setProcessEnvironment(env); ``` 4. **安全终止机制**: - 先发送 `SIGTERM` (kill -15) 允许程序清理资源 - 1秒后发送 `SIGKILL` (kill -9) 强制终止 ### 替代方案:纯Qt实现重 ```cpp void restartWithoutScript() { QString appPath = QCoreApplication::applicationFilePath(); QStringList args = QCoreApplication::arguments(); QProcess::startDetached(appPath, args); QCoreApplication::exit(0); } ``` ### 调试技巧 1. 检查脚本执行日志: ```cpp process->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(process, &QProcess::readyRead, [=](){ qDebug() << "脚本输出:" << process->readAll(); }); ``` 2. 验证进程状态: ```bash # 重后检查进程 ps aux | grep your_qt_app ``` 3. 内核日志分析: ```bash dmesg | grep -i qt ``` ### 常见问题解决 | 问题现象 | 解决方案 | |---------|---------| | 脚本未执行 | 检查文件权限 `ls -l restart_qt.sh` | | 环境变量丢失 | 在脚本中显式设置 `export DISPLAY=:0` | | 进程残留 | 增加 `pkill -f "my_qt_app"` 双重保障 | | 动延迟 | 在 `nohup` 前添加 `sleep 0.5` | --- ### 相关问题 1. 如何在Qt中捕获脚本执行结果并显示在GUI中? 2. Ubuntu系统下如何防止Qt程序重复动? 3. 怎样在Qt中实现应用程序的静默自动更新? 4. 跨平台(Windows/Linux)的重方案如何设计? 5. 如何通过Qt实现系统守护进程监控应用程序状态? > 提示:在正式部署前,建议使用虚拟终端测试脚本行为: > ```bash > xvfb-run bash restart_qt.sh # 无界面测试 > ```[^1][^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值