Starting an interactive shell in Linux
-
wrote on 21 Sept 2022, 11:58 last edited by
I've client/server app in which I want to start an interactive shell/terminal on client side upon request from server. Is their a generic utility which works as an interactive shell on all major Linux systems for example, sh utility in linux ?
Should i use QProcess to start sh and then try to read/write to its STD I/O or is their another way to achieve interactive shell behaviour?
Thanks
-
I've client/server app in which I want to start an interactive shell/terminal on client side upon request from server. Is their a generic utility which works as an interactive shell on all major Linux systems for example, sh utility in linux ?
Should i use QProcess to start sh and then try to read/write to its STD I/O or is their another way to achieve interactive shell behaviour?
Thanks
wrote on 21 Sept 2022, 12:21 last edited by@pingal
/bin/sh
is always available under Linux, if that is what you mean.If you need/want to interact with a program you spawn, in the sense of writing to its input and/or reading from its output, then yes use
QProcess
and you can do that (per the docs).Whether that applies to your "interactive shell/terminal" is another matter.
sh
won't show any window to the user anyway. What is your "interactivity", what are you actually needing to do? -
@pingal
/bin/sh
is always available under Linux, if that is what you mean.If you need/want to interact with a program you spawn, in the sense of writing to its input and/or reading from its output, then yes use
QProcess
and you can do that (per the docs).Whether that applies to your "interactive shell/terminal" is another matter.
sh
won't show any window to the user anyway. What is your "interactivity", what are you actually needing to do? -
The purpose is to get the /bin/sh interface of the client so that server user can interact with the client shell remotely. Just like someone login to a remote machine using ssh, for example.
wrote on 22 Sept 2022, 08:09 last edited by JonB@pingal
Yes, sh functions like ssh. But I'm still not clear what you want the "interactivity" for. Neither one opens any kind of "visual window" of their own. You have two basic ways you can drive them:-
You can run them in a terminal, such as xterm. That will open an X window. The user can then sit in front of it, type commands, and see the output. But in that "interactivity" your Qt application cannot send commands and "see" the output, only the user sitting there can.
-
You can run them directly from your Qt program. But that will not open any window for the user to see/interact with. Your Qt application can send commands to it by writing
to its stdoutonQProcess
which will arrive at the shell's stdin, and can collect what the shell writes to its stdout/stderr and then show it to the user e.g. in a widget. But your Qt program has to do this writing & reading for each command. At which point, it is not clear that you really want an "interactive" shell at all. You might just as well send each command and receive its output each time, without leaving any "interactive shell" running at all. In the case of ssh it might be worth it because of the overhead of having to "authenticate" each time, but sh really does not do a lot for you. You might even send the commands directly without an interposing sh, depending on what the commands are.
I suppose I ought to have verified from the beginning: is your Qt program a UI one, with windows and widgets, or is it just a command-line one, with no UI widgets? If it is the latter you would run it from a terminal (e.g. xterm).
-
-
@pingal
Yes, sh functions like ssh. But I'm still not clear what you want the "interactivity" for. Neither one opens any kind of "visual window" of their own. You have two basic ways you can drive them:-
You can run them in a terminal, such as xterm. That will open an X window. The user can then sit in front of it, type commands, and see the output. But in that "interactivity" your Qt application cannot send commands and "see" the output, only the user sitting there can.
-
You can run them directly from your Qt program. But that will not open any window for the user to see/interact with. Your Qt application can send commands to it by writing
to its stdoutonQProcess
which will arrive at the shell's stdin, and can collect what the shell writes to its stdout/stderr and then show it to the user e.g. in a widget. But your Qt program has to do this writing & reading for each command. At which point, it is not clear that you really want an "interactive" shell at all. You might just as well send each command and receive its output each time, without leaving any "interactive shell" running at all. In the case of ssh it might be worth it because of the overhead of having to "authenticate" each time, but sh really does not do a lot for you. You might even send the commands directly without an interposing sh, depending on what the commands are.
I suppose I ought to have verified from the beginning: is your Qt program a UI one, with windows and widgets, or is it just a command-line one, with no UI widgets? If it is the latter you would run it from a terminal (e.g. xterm).
wrote on 22 Sept 2022, 10:38 last edited by pingalI've spawned /bin/sh as a QProcess and commands I receives from server app is being written to it and output is read from it and send to server accordingly. So this somehow mimic interactivity and it works.
The problem I'm facing now is when i write "exit" to the spawned process (i.e. /bin/sh) from my client app, it exit my whole client app.
Here is how i'm spawning and writing command(s) to it
if(shell == nullptr){ // If the shell is not running, spawn it shell = new QProcess(this); #if defined (__linux__) || defined (__unix__) QString pathToShell("/bin/sh"); #endif QObject::connect(shell, &QProcess::started, this, [](){qDebug() << "/bin/sh started";}); QObject::connect(shell, &QProcess::readyRead, this, [this](){emit sendToServer(shell->readAllStandardOutput());}); connect(shell, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](int exitCode, QProcess::ExitStatus exitStatus){ qDebug()<< QFileInfo(shell->program()).fileName() << "is finished with Exit Code:"<< exitCode << " ExitStatus:"<< exitStatus; shell->deleteLater();shell=nullptr;}); shell->start(pathToShell); } // If shell is running, Submit commands to its STDIN if(!RecievedCommand.isEmpty() && shell != nullptr){ RecievedCommand.append("\n"); shell->write(RecievedCommand.toStdString().c_str()); }
-
-
I've spawned /bin/sh as a QProcess and commands I receives from server app is being written to it and output is read from it and send to server accordingly. So this somehow mimic interactivity and it works.
The problem I'm facing now is when i write "exit" to the spawned process (i.e. /bin/sh) from my client app, it exit my whole client app.
Here is how i'm spawning and writing command(s) to it
if(shell == nullptr){ // If the shell is not running, spawn it shell = new QProcess(this); #if defined (__linux__) || defined (__unix__) QString pathToShell("/bin/sh"); #endif QObject::connect(shell, &QProcess::started, this, [](){qDebug() << "/bin/sh started";}); QObject::connect(shell, &QProcess::readyRead, this, [this](){emit sendToServer(shell->readAllStandardOutput());}); connect(shell, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](int exitCode, QProcess::ExitStatus exitStatus){ qDebug()<< QFileInfo(shell->program()).fileName() << "is finished with Exit Code:"<< exitCode << " ExitStatus:"<< exitStatus; shell->deleteLater();shell=nullptr;}); shell->start(pathToShell); } // If shell is running, Submit commands to its STDIN if(!RecievedCommand.isEmpty() && shell != nullptr){ RecievedCommand.append("\n"); shell->write(RecievedCommand.toStdString().c_str()); }
@pingal said in Starting an interactive shell in Linux:
it exit my whole client app
Should not happen. Did you debug your client app to see what exactly happens? Maybe it is crashing?
-
@pingal said in Starting an interactive shell in Linux:
it exit my whole client app
Should not happen. Did you debug your client app to see what exactly happens? Maybe it is crashing?
-
I've spawned /bin/sh as a QProcess and commands I receives from server app is being written to it and output is read from it and send to server accordingly. So this somehow mimic interactivity and it works.
The problem I'm facing now is when i write "exit" to the spawned process (i.e. /bin/sh) from my client app, it exit my whole client app.
Here is how i'm spawning and writing command(s) to it
if(shell == nullptr){ // If the shell is not running, spawn it shell = new QProcess(this); #if defined (__linux__) || defined (__unix__) QString pathToShell("/bin/sh"); #endif QObject::connect(shell, &QProcess::started, this, [](){qDebug() << "/bin/sh started";}); QObject::connect(shell, &QProcess::readyRead, this, [this](){emit sendToServer(shell->readAllStandardOutput());}); connect(shell, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](int exitCode, QProcess::ExitStatus exitStatus){ qDebug()<< QFileInfo(shell->program()).fileName() << "is finished with Exit Code:"<< exitCode << " ExitStatus:"<< exitStatus; shell->deleteLater();shell=nullptr;}); shell->start(pathToShell); } // If shell is running, Submit commands to its STDIN if(!RecievedCommand.isEmpty() && shell != nullptr){ RecievedCommand.append("\n"); shell->write(RecievedCommand.toStdString().c_str()); }
wrote on 22 Sept 2022, 13:46 last edited by@pingal
Your code is good. However you have not connected to read anything written on standard error in the shell, and you should certainly do so! Either call as wellshell->readAllStandardError()
in yourreadyRead()
slot and/or useQProcess::readReadStandardOutput
/Error()
signals instead ofreadyRead()
, or use setProcessChannelMode(QProcess::MergedChannels). -
@pingal
Your code is good. However you have not connected to read anything written on standard error in the shell, and you should certainly do so! Either call as wellshell->readAllStandardError()
in yourreadyRead()
slot and/or useQProcess::readReadStandardOutput
/Error()
signals instead ofreadyRead()
, or use setProcessChannelMode(QProcess::MergedChannels).
1/9