Run Commands in terminal using Qprocess in Ubuntu
-
Hi, I am trying to run a simple ls command in terminal in ubuntu.My expectation is to open a terminal and execute the command , show the results and wait till the user closes the terminal.
QProcess terminalProcess1;QObject::connect(&terminalProcess1, &QProcess::stateChanged, [](QProcess::ProcessState newState) { qDebug() << "Process = "<< newState; }); QObject::connect(&terminalProcess1, &QProcess::readyReadStandardError, [&terminalProcess1]() { QByteArray data = terminalProcess1.readAllStandardError(); qDebug() << "Standard Error Output:" << data; }); QObject::connect(&terminalProcess1, &QProcess::readyReadStandardOutput, [&terminalProcess1]() { QByteArray data = terminalProcess1.readAllStandardOutput(); qDebug() << "Standard Output:" << data; }); QString workingDirectory = QDir::currentPath() + "/Tools/velodyne_ws"; terminalProcess1.setWorkingDirectory(workingDirectory); QStringList arguments1; arguments1<<"-hold" << "-e" << "ls"; terminalProcess1.start("/usr/bin/x-terminal-emulator",arguments1);
Output:
Process = QProcess::Starting
QProcess: Destroyed while process ("/usr/bin/x-terminal-emulator") is still running.
Process = QProcess::Running
Process = QProcess::NotRunningI am not sure whether I am doing this right or not .Thanks for the help in advance
P.S: Path is not the issue .I have checked it multiple times
-
@Adithya said in Run Commands in terminal using Qprocess in Ubuntu:
QProcess: Destroyed while process ("/usr/bin/x-terminal-emulator") is still running.
Looks like your terminalProcess1 is a local stack allocated variable and goes out of scope and thus is deleted.
Add error handling to your code.
Why do you need to execute ls to get content of a folder? You can do that with Qt without launching an external process. And if you really want to execute ls command but don't need terminal window simply execute ls command instead of /usr/bin/x-terminal-emulator. -
@jsulm Hi , I made terminalProcess1 as a member variable which resolves the error I was getting ,but the terminal is getting closed in a flash .My expectation is to open terminal and not close until the user chooses to close the terminal . Is there anything I need to change in my code
I used terminalProcess1.waitForFinished(); but didnt work -
@Adithya said in Run Commands in terminal using Qprocess in Ubuntu:
but the terminal is getting closed in a flash
As I wrote: if it is a local variable it goes out of scope and is deleted - basic C/C++. If you want to keep it make it class member.
Also, /usr/bin/x-terminal-emulator only starts for me if I do not pass the parameters you pass. It does not look like /usr/bin/x-terminal-emulator supports these commands (check with -h parameter to see what parameters it supports).
To do what you want to do you will need to start the terminal and then write the ls command to it's stdin. Or start bash command with -c parameter followed by the command you want to execute. -
,but the terminal is getting closed in a flash .
If the terminal process exits and closes its window then QProcess will report that (but it has no control over it).
chrisw@newton:~$ x-terminal-emulator -hold -e ls konsole: Unknown options: o, l, d.
The option for
x-terminal-emulator
is--hold
not-hold
. -
@Adithya
As @ChrisW67 says, if the option is supported at all it is--hold
(or-H
). But not all Linux flavors support it. You should always test a command like this first outside of Qt from a terminal to check it is right.Once you made the
QProcess
a persistent variable, you ought to have got a "usage" error for-hold
reported through yourQObject::connect(&terminalProcess1, &QProcess::readyReadStandardError
connection. But never mind now.When you move this onto your real "ROS-velodyne tool", what will you be trying to do with that once it is launched? Will the user just look at the terminal window and/or type into it manually? Will you be wanting your Qt program to send it input/commands and/or will you expect to "see" its output in your code?
-
@JonB I want to send the command through qt .The user just has to ensure that the tool is running as expected and close once the job is done as It does not close automatically . But I am stuck as I am able to launch x-terminal-emulator but it is not taking any arguments as @jsulm mentioned . I tried to use write() aswell to send the command through stdin .But it is not helping , is there any other way ? or am I not doing it right ?
terminalProcess1.start("/usr/bin/x-terminal-emulator"); terminalProcess1.write("ls");
-
@Adithya said in Run Commands in terminal using Qprocess in Ubuntu:
I am able to launch x-terminal-emulator but it is not taking any arguments as @jsulm mentioned
I don't know what this means. Can you please forget about Qt, just go to a terminal and as @ChrisW67 said enter
x-terminal-emulator --hold -e ls
and tell us what happens? Either you get an error message or it should open the terminal, run the
ls
, show that output, and then sit there looking at you waiting for input. Which of these happens?ACTUALLY WAIT. Which exact OS are you running? And if you go
man x-terminal-emulator
do you get the man page forGNOME-TERMINAL(1)
as i do under Ubuntu 22.04? -
@JonB x-terminal-emulator --hold -e ls -> this command opens a new terminal in a flash and exits
x-terminal-emulator --hold ls -> opens a new terminal but ls command is not sent to the new terminal as a argument
/bin/sh -c ls -> executes the command and provides output but no terminal is opened just the output can be printed using readAllStandardOutput()yes it is navigating to GNOME-TERMINAL(1) .I am running on ubuntu 20.04
-
@Adithya
Yeah, I am having issue too. Please start by answering the two questions I appended above after ACTUALLY WAIT.Oh, I see you are Ubuntu. 22.04? Are you wedded to using
x-terminal-emulator
/gnome-terminal
or would you considerxterm
(which may need installing)? I don't mind, and will figure out whichever, but want to know what you want first. -
@Adithya
OK. Having looked now. It does not matter whether you usex-terminal-emulator
/gnome-terminal
orxterm
nor whether you pass that either-e
nor-x
. Neither of these runs your command (ls
or whatever) as the first thing after opening a window with a shell. Rather any command passed like this replaces the shell with whatever you specify. That is quite different. And useless to you (at least forls
).Before we go any further. You are intending to "launch a ROS-velodyne tool". I need to know what that is/how it works. Is it a "shell", i.e. does this tool sit and wait for user input/commands and then interpret them, do something, and return to sitting there waiting for you? Like
/bin/bash
orpython3
would do? Or is it just like e.g.ls
, where it does something and then exits, not any kind of "waiting shell"? -
@JonB Lets just say its just a executable which I am running through terminal.The input is sent command line arguments .Logs will be pouring ,just need to check whether it is doing its job or not from the logs ,if not user must be able to press ctrl+c and re run the tool again . Once done , user needs to close the terminal .pretty much it
-
@Adithya
Not totally clear! I am going to guess you mean:- Program is run, with some command line arguments.
- The "logs" you speak of are being to sent to stdout (not to a log file), you want user to see these pouring down a window.
- User can "interrupt" this if they don't like what they see, so they don't have to wait till the end.
- But if they do wait till the end you want the window to remain, even though the program has finished running, so they can view the output and scroll up and down, before closing the terminal.
At no point is your "ROS-velodyne tool" acting like a "shell". It never allows the user to type a new command into it, nor do you want to be able to send it a command (e.g. on its stdin) once it is running, it only accepts whatever on the command line in the first place. So much like
ls
!We may have a problem here, trying to do that in a terminal window. I will investigate further.
man x-terminal-emulator
claims you can run e.g.gnome-terminal -- sh -c ...
but I'm not even finding this works....However, would you consider the following. I don't know whether your Qt program is command-line only or GUI? Without involving a shell or a window we could run the command from Qt and *read its output as it goes copying that to some kind of Qt window (UI) or stdout (comamnd-line). You would (probably) handle Ctrl+C in your Qt program,
kill()
ing the ROS tool sub-process yourself if the user tells you to stop. How "preferable" or "unsuitable" would you consider such an approach? -
@Adithya
For that one. You justQProcess::start()
your "ROS Tool", no "terminal". You connect to slotreadyReadStandardOutput
/Error()
. That will be hit repeatedly as new input from the log output arrives. You do areadAll()
there and copy that output to your own window/widget, e.g. aQPlainTextEdit
(with scrolling). Put it in some kind ofQWidget
(with layout) and a STOP button. If user clicks that you do aQProcess::terminate
/kill()
. I have done this before. But it is a little bit of work. Advantage is you too can examine output, if you wish, but you may not need or want that.Meanwhile I will continue having a look at what you originally wanted, some kind of "terminal" which runs the command and lets user see output in a window (maybe allows Ctrl+C too, not sure). So gibe me a few minutes before giving up on that and having the take the approach above. Unless you prefer that over a terminal anyway, in which case please let me know so I don't spend too much on it.... :)
-
@Adithya
OK, usingxterm
I can give you just what you want:xterm -hold -e find / -print
- If the user waits till the end they can click the "X" to close the window.
- If they get fed up watching the output roll by (that is why I picked
find / -print
, loads of output) they can press Ctrl+C in the window and it stops, then close it.
These days I believe
xterm
is no longer installed by default in Ubuntu, you have toapt get
it. I will continue to have a look at whether I can do this inx-terminal-emulator
/gnome-terminal
... -
@Adithya
For GNOME terminal I am not finding anything quite as neat. Howevergnome-terminal -- sh -c 'find / -print ; read x'
does the job reasonably (you put your command in place of
find / -print
, but keep the; read x
after it).- If the user waits till the end they can click the "X" to close the window or press ENTER key.
- If they get fed up watching the output roll by they can press Ctrl+C in the window. This closes the window immediately.
-