How to check if a program exists in path using Qt? - c++

I have this code:
QProcess* proceso = new QProcess();
QString programa = "unknow -v";
proceso->start(programa);
proceso->waitForFinished();
QString normal = proceso->readAllStandardOutput();
QString errores = proceso->readAllStandardError();
qDebug() << normal;
qDebug() << errores;
The output I get is:
""
""
But I want get and error that says: Command not found.
Thanks in advance.
EDITED:
I found this solution using Qt:
int result = system("unknow -v");
if(result!=0) {
qDebug() << "No está instalado nasm";
} else {
qDebug() << "Está instalado.";
}
But I want get an output into a QString.

You could fetch the value of your PATH using getenv("PATH") then split it on colons (or semi-colons for Windows), iterate on every directory there, test that it contains a unknow file, etc....
So you don't need any Qt thing for that. Just plain C++ (string operations).
(this is not bullet-proof: some other process might modify a directory in your $PATH between such a test and the actual start of process; but it should often be enough in practice)
On POSIX systems, you might run your command thru sh -c (e.g. run sh -c 'unknow -v'), but be careful of escapes and code injections (so check the string unknow -v for things like single and double quotes, etc...)
You could also use popen(3) perhaps using which but I don't recommend that (too complex).
I am not sure it is worth the trouble anyway. Why don't you simply just run the program.... I don't see much difference between a missing executable and a command failing for many other reasons.

Please try this:
QProcess program;
QString commandToStart= "unknown -v";
QStringList environment = program.systemEnvironment();
program.start(commandToStart);
bool started = program.waitForStarted();
if (!program.waitForFinished(10000)) // 10 Second timeout
program.kill();
int exitCode = program.exitCode();
QString stdOutput = QString::fromLocal8Bit(program.readAllStandardOutput());
QString stdError = QString::fromLocal8Bit(program.readAllStandardError());
If started is true, the program could be started. That usually means, it was in the path. If it's false, check whether the path in environment is correct.
The exitCode is only helpful, if the process could actually be started and something else went wrong. If the program could not be started at all, exitCode will be 0 and stdOutput and stdError will be empty! That may be misleading.

The question is about if you are able to run the command aka if the command exists on your system. This means NOT trying to launch it and see what happens, huge difference!
How about this?
I like the idea of which but it won't work under Windows, AFAIK.
QProcess findProcess;
QStringList arguments;
arguments << myCommand;
findProcess.start("which", arguments);
findProcess.setReadChannel(QProcess::ProcessChannel::StandardOutput);
if(!findProcess.waitForFinished())
return false; // Not found or which does not work
QString retStr(findProcess.readAll());
retStr = retStr.trimmed();
QFile file(retStr);
QFileInfo check_file(file);
if (check_file.exists() && check_file.isFile())
return true; // Found!
else
return false; // Not found!

Related

What is the correct way to execute a CMD command with QProcess to get the output as QString?

I'm new using QT, I need to execute a CMD command on windows and get the output of this command as a string to later process and get specific data. The following code works well (it seems to work well). The only problem is that I get the following warning: "start is deprecated", I think this warning message is because the start method needs an arguments list as parameter.
QString command = "tasklist /FI \"IMAGENAME eq notepad.exe\"";
QProcess *executeCommand = new QProcess();
executeCommand->start(command);
executeCommand->waitForFinished(-1);
QString output = executeCommand->readAllStandardOutput();
executeCommand->terminate();
qDebug() << commandOutput;
how can I remove this warning message?
Also I found in the web that I can use system() to execute a CMD command, but I'm not able to catch the output as string.
Another question: which of the above options is better to achieve what I'm trying to do, the QProcess or System (if is possible to get the output as QString)?
Thanks in advance!
There is an answer read QProcess output to string recommending static method QProcess::readAllStandardOutput() returning QByteArray. Then just instantiate QString from QByteArray implicitly.
If you are working on Qt application, it is better to stay inside Qt API to keep the code more or less portable.

Using QProcess to read standard output

In my QT widget application I am attempting to run a shellscript that opens a C++ program and provides inputs to the program as well. The program starts a command prompt that requires the users input to start. Once the program is started the output of the program is redirected via the standard output to a text file. I am attempting to use QProcess to open and run this shellscript, then read the standard output that is being used to print the result of the C++ program to the text file. The shell script only runs this process and does not terminate it. This is because I need to continuously read this output into the GUI as the program is running. It will not be sufficient to wait until the program is finished to read this information. I am fairly new to QT and C++ programming. I was hoping that someone could help me with my implementation of this.
QProcess process;
process.start("/home/pi/Desktop/ShellScripts/RunTutorial3.sh");
QString output =process.readAllStandardOutput();
qDebug() << output;
QString err = process.readAllStandardError();
qDebug() << err;
I have experimented with using other read function such as readline and also trying to start the process as a detatched process. I have not had success with any of my experimentations. Is it possible to do what I am attempting in QT. I just need the program to run continuously and for QT to read this output every so often.
Shell script:
#!/bin/bash
cd
cd Desktop
cd tutorial3App
cd bin
echo "start" | ./tutorial3
C++ code: I need the meanTOE value to be captured in standard output to use in my GUI.
/ Calculate average time to end of discharge
double meanToE = std::accumulate(ToESamples.begin(), ToESamples.end(), 0.0)/ToESamples.size();
file << ": EOL in " << meanToE << " s" << std::endl;
As I said in my comments one of the main problems is that when you run tutorial3 that process is separated so you can not get the output. Therefore, I recommend executing it directly, and QProcess is probably a local variable, eliminating after printing an empty text, a possible solution is to create a pointer. Another improvement would be to use the readyReadStandardOutput and readyReadStandardError signals since the impressions are not automatic.
QProcess *process = new QProcess(this);
connect(process, &QProcess::readyReadStandardOutput, [process, this](){
QString output =process->readAllStandardOutput();
qDebug() << "output: "<< output;
});
connect(process, &QProcess::readyReadStandardError, [process](){
QString err = process->readAllStandardError();
qDebug() << "error: "<<err;
});
process->setWorkingDirectory("/home/pi/Desktop/tutorial3App/bin/")
process->start("tutorial3", QStringList() << "start");
I think you have to read about signals and slots in Qt. QProcess has got a signal readyReadStandardOutput. So you have to connect to this signal and in your slot you should use QProcess function readAllStandardOutput. In other words when your shell programm outputs something you catch it in your slot and dump it or whatever you want.
Check the answer on this question. It might help you.
reading and writing to QProcess in Qt Console Application

QProcess issue in executing a exe with arguments

I have a issue in setting the QProcess to run executable with the arguments. The Qt code for the same is as below,
QString program = "C:\Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
The output of this snippet is to uninstall some program. But it is not happening. Am i doing any mistake?
But if I go to cmd prompt and execute the same thing like.,
c:/> "C:/Setup.exe" -uninstall
This works perfectly.
There are at least two options to solve your issue.
Use '/' for directory separators as per documentation:
If you always use "/", Qt will translate your paths to conform to the underlying operating system.
Escape the backslash whenever working with file paths as string as per an example from the documentation:
env.insert("TMPDIR", "C:\\MyApp\\temp"); // Add an environment variable
env.insert("PATH", env.value("Path") + ";C:\\Bin");
Therefore, you should be writing something like this:
QString program = "C:/Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
or this:
QString program = "C:\\Setup.exe";
QStringList arguments;
arguments << "-uninstall";
QProcess::startDetached(program, arguments);
In general, when facing such issues, you could always print out the error string to get more information by using the following syntax:
qDebug() << myProcess.errorString();
This, for sure, needs an instance, however.

Qt - How to output Windows PowerShell error message via QProcess

I am working in Qt 4.7, and I have a program that needs to use a QProcess to output the result of running a Windows PowerShell command. For the purposes of this question, let's say all that needs to be supported is use of the "-Command" option. Right now I have this:
QString path = "C:/windows/system32/WindowsPowerShell/v1.0/powershell.exe";
QStringList command;
command.append("-Command");
command.append(/*Whatever test command I want to use...*/);
process = new QProcess(); //Note: QProcess *process is a member of this class
connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(/*slot to print qprocess errors...*/);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(/*slot to display PowerShell output...*/);
process->start(path, command);
The slot to print the PowerShell output is simply as follows:
std::cout << "RESULT: " << QString(process->readAllStandardOutput()).toStdString() << std::endl;
This works perfectly with correct PowerShell commands. For example, I tested it with the command "Get-ChildItem C:\", and it printed the correct data. It also works fine if there is a QProcess error. What I need to know how to do is, how can I have it print a PowerShell error message? For example, if I try to use the command "Get-ChildIte" (missing the m at the end) directly in PowerShell I get an error message. But with my code, it just doesn't print anything. I need it to print that error message. If anyone knows of a way this could be done, I'd really appreciate it. Thanks!
Ok, you posted your answer 7 seconds ago. I just wanted to confirm, and give a link to reference for you that may help troubleshoot this in the future.
QProcess Class
Yes, you want the readAllStandardError() function of QProcess.
So, about a minute after I posted this I discovered QProcess's signal readyReadStandardError(), which operates identically to readyReadStandardOutput except that it is emitted when whatever the QProcess is running has an error. I connected this to a slot identical to what I have above but instead printing QString(process->readAllStandardError()).toStdString() and it worked.

Problems passing source command to bash from c++ application

I am developing an application for work that allows the users to quickly set environment variables on a terminal basis. By setting the path in each terminal we ensure files with the same name in different directories aren't causing application testing to be problematic. I am Using Qt to build the program which is c++ based and all the datatypes are foundationally the same.
I am using the following code to invoke commands in the terminal from which the application launches from using system(). I can run commands into the bash just fine with code; however, I run into a problem when I attempt to use a command with arguments. This is probably why source doesn't seem to work right as the source command is followed by the filename. It would appear that I drop the argument appended after the bash command.
My Code:
void assignTerminalToPath(QString path)
{
QString data = "";
QString currentUsersHomeDirectory = QDir::homePath();
QString tmpScriptLocation = currentUsersHomeDirectory;
QByteArray ba;
tmpScriptLocation += "/.tmpSourceFile";
QFile tmpSourceFile(tmpScriptLocation);
if(tmpSourceFile.open(QFile::WriteOnly | QFile::Truncate))
{
QTextStream output(&tmpSourceFile);
data.append("export PATH=.:");
data.append(path);
data.append(":$PATH");
output << QString("#!/bin/bash\n");
output << data;
tmpSourceFile.close();
}
data.clear();
data.append("/bin/bash -c source ");
data.append(tmpScriptLocation);
ba = data.toLatin1();
const char *cStr = ba.data();
system(cStr);
}
Perhaps I'm not referencing bash correctly and I need something outside of -c?
Reference Execute shell/bash command using C/C++
Thanks for any help in advance!
source is not a program that you can call, it is embedded bash command. It is designed to be processed by bash without invoking another copy of bash, such that environment variables can be changed in current bash copy.
However, you cannot call source as part of system(). And even if you did succeed at that, its effects to change environment variables would be completely lost for caller app once system() has returned.
Try a command to envelop with parameters in double quotes ("command - arg1 - to arg2") to transfer in the function system().
used:
char *com = "\"command -arg1 -arg2\"";
system(com);