2017-01-25 2 views
1

Bekannt: dies scheint eine spezifische Frage Frage zu sein, aber hoffentlich kann es für alle im Zusammenhang mitLesen und Schreiben auf QProcess in Qt Console Application

Ich muss mit einem QProcess Objekt zu interagieren bearbeitet werden.

Das Problem:

ich von QProcess nach dem Aufruf QProcess:write(input)

Mehr Infos bin keine Ausgabe bekommen:

Geht man durch die doc pages führte mich unter ein Beispiel zu erstellen:

Ich habe ein Skript, das Benutzereingaben anfordert und schließlich anzeigt und eine geeignete Nachricht basierend auf der Benutzereingabe.

Testing:

Nach dem Hinzufügen einer "log" -Funktion, um mein Skript für die Prüfung, geschieht Folgendes:

  • Skript führt
  • Skript Benutzereingabe anfordert (die ‚erste bestätigt 'qDebug() << p->readAll())
  • Skript akzeptiert Eingabe von QProcess (bestätigt durch Skript' Protokollausgabe ')

Danach wird keine Ausgabe empfangen. Die folgenden 2 debug Aussagen sowohl Feuer (d 30s warten jeweils)

if (!p->waitForReadyRead()) { 
    qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
} 
if (!p->waitForFinished()) { 
    qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
} 

Gefolgt von:

QString s = QString(p->readAll() + p->readAllStandardOutput()); 

wo s eine leere Zeichenfolge ist.

Die Frage ist ssollte entweder "Erfolg" oder "nicht bestanden"

Aufrufen von Code enthalten:

QString cmd = QString("sh -c \"/path/to/bashscript.sh\""); 
QString input = QString("Name"); 
QString result = runCommand(cmd, input) 

Prozess Code:

//takes 2 parameters, 
// cmd which is the code to be executed by the shell 
// input which acts as the user input 

QString runCommand(QString cmd, QString input){ 
    QProcess *p = new QProcess(new QObject()); 
    p->setProcessChannelMode(QProcess::MergedChannels); //no actual reason to do this 
    p->start(cmd); 
    if (p->waitForStarted()) { 
     if (!p->waitForReadyRead()) { 
      qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
     } 
     if (!p->waitForFinished()) { 

      //reads current stdout, this will show the input request from the bash script 
      //e.g. please enter your name: 
      qDebug() << p->readAll(); 

      //here I write the input (the name) to the process, which is received by the script 
      p->write(ps.toLatin1()); 

      //the script should then display a message i.e. ("success" o "failed") 
      if (!p->waitForReadyRead()) { 
       qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
      } 
      if (!p->waitForFinished()) { 
       qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
      } 
     } 
     QString s = QString(p->readAll() + p->readAllStandardOutput()); 
     return s; 
    } 
    else{ 
     qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
    } 
    p->waitForFinished(); 
    p->kill(); 
    return QString(); 
} 

script.sh (-rwxrwxr-x)

#!/bin/bash 
#returns 
# "success" on non empty $n value 
# "failed: on empty $n value 
# 
echo "enter your name:" 
read n 
if [[ ! -z $n ]]; 
then 
     echo "success" 
     exit 0; 
else 
     echo "failed" 
     exit 1; 
fi 

UPDATE

@KevinKrammer ich den Startbefehl geändert, wie Sie gesagt hat, auch den QStringList mit dem args verwenden.

Immer noch nicht ausgegeben, tatsächlich die waitForReadyRead() und waitForFinished()returns false sofort.

Called mit:

QString r = runCommand(QString("text")); 

Prozess Code:

QString runCommand(QString input){  

    QProcess *p = new QProcess(new QObject());  
    p->setProcessChannelMode(QProcess::MergedChannels); 

    //script is the same script refered to earlier, and the `cd /home/dev` IS required 
    p->start("sh", QStringList() << "-c" << "cd /home/dev" << "./script"); 
    ; 
    if (p->waitForStarted()) { 
     if (!p->waitForReadyRead(5000)) { 
      qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
     } 
     qDebug() << p->readAll(); 
     p->write(input.toLatin1()); 
     if(!p->waitForFinished(5000)){ 
      qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
     } 
     QString s = QString(p->readAll() + p->readAllStandardOutput()); 
     return s; 
    } 
    else{ 
     qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); 
    } 
    p->waitForFinished(); 
    p->kill(); 
    return QString(); 
} 

Terminal-Ausgabe des Prozesses:

started 
readChannelFinished 
exit code = "0" 
waitForReadyRead() [false] : CODE: "5" | ERROR STRING: "Unknown error" 
"" 
waitForFinished() [false] : CODE: "5" | ERROR STRING: "Unknown error" 
Press <RETURN> to close this window... 

Gedanken dazu?

UPDATE 2

@Tarod Vielen Dank für die Zeit nehmen, um eine Lösung herzustellen.

Es funktioniert, wird jedoch nicht vollständig erwartet.

Ich kopierte über Ihren Code, genau.

ein paar Änderungen in der

Sehen Sie weitere Informationen unter mReadyReadStandardOutput() gemacht.

Das Problem:

Nach dem Ausführen der Anwendung (und Skript), erhalte ich ein Ergebnis -> FANTASTISCHEN

Jedesmal, es ist das falsche Ergebnis heißt "nicht bestanden". -> NICHT FANTASTISCHEN

Terminal-Ausgang:

void MyProcess::myReadyRead() 
void MyProcess::myReadyReadStandardOutput() 
"enter your name:\n" 
"" 
void MyProcess::myReadyRead() 
void MyProcess::myReadyReadStandardOutput() 
"failed\n" 
Press <RETURN> to close this window... 

Skriptinhalt:

#!/bin/bash 
echo "enter your name:" 
read n 
echo $n > "/tmp/log_test.txt" 
if [[ ! -z "$n" ]]; 
then 
     echo "success" 
     exit 0; 
else 
     echo "failed" 
     exit 1; 
fi 

/tmp/log_test.txt Ausgang

myname 

diese läuft manuell von der Konsole:

[email protected]:~$ ls -la script 
-rwxrwxr-x 1 dev dev 155 Jan 25 14:53 script* 

[email protected]:~$ ./script 
enter your name: 
TEST_NAME 
success 

[email protected]:~$ cat /tmp/log_test.txt 
TEST_NAME 

Voll Code:

#include <QCoreApplication> 
#include <QProcess> 
#include <QDebug> 

class MyProcess : public QProcess 
{ 
    Q_OBJECT 

public: 
    MyProcess(QObject *parent = 0); 
    ~MyProcess() {} 

public slots: 
    void myReadyRead(); 
    void myReadyReadStandardOutput(); 
}; 

MyProcess::MyProcess(QObject *parent) 
{ 
    connect(this,SIGNAL(readyRead()), 
      this,SLOT(myReadyRead())); 
    connect(this,SIGNAL(readyReadStandardOutput()), 
      this,SLOT(myReadyReadStandardOutput())); 
} 

void MyProcess::myReadyRead() { 
    qDebug() << Q_FUNC_INFO; 
} 

void MyProcess::myReadyReadStandardOutput() { 
    qDebug() << Q_FUNC_INFO; 
    // Note we need to add \n (it's like pressing enter key) 
    QString s = this->readAllStandardOutput(); 
    qDebug() << s; 
    if (s.contains("enter your name")) { 
     this->write(QString("myname" + QString("\n")).toLatin1()); 
     qDebug() << this->readAllStandardOutput(); 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    MyProcess *myProcess = new MyProcess(); 

    QString program = "/home/dev/script"; 

    myProcess->start("/bin/sh", QStringList() << program); 

    a.exec(); 
} 

#include "main.moc" 

Skript Ausgabe? QProcess-Problem?

+0

warum Sie 'waitForFinished' fordern vor dem Schreiben? Gegeben Ihr Programm würde die Reihenfolge warten auf Start, dann Schleife auf Warten auf Lesen, bis Sie die erwartete Zeichenfolge erhalten haben, die schreiben, dann warten auf fertig. Für den Befehl würde ich auch empfehlen, Befehl und Argumente separat zu übergeben, d. H. Den Befehl als erstes Argument für 'start()' und alle seine Parameter als zweiten, da dies auch korrekt und automatisch spacing behandelt. –

+0

@KevinKrammer Vielen Dank für den Vorschlag, ich werde es anwenden und mit einem Ergebnis – KGCybeX

+0

@KevinKrammer zurückkehren, die ein Nein ist. Bitte sehen Sie update – KGCybeX

Antwort

2

Leider habe ich nicht Ihren ganzen Code, also habe ich ein Beispiel gemacht. Ich hoffe es hilft dir.

Wenn ich meinen Code mit Ihrem vergleiche, denke ich, das Problem könnte sein, dass Sie nach dem Schreiben nicht readAllStandardOutput() anrufen oder vielleicht rufen Sie nicht exec() in Ihrem main.cpp.

#include <QCoreApplication> 
#include <QProcess> 
#include <QDebug> 

class MyProcess : public QProcess 
{ 
    Q_OBJECT 

public: 
    MyProcess(QObject *parent = 0); 
    ~MyProcess() {} 

public slots: 
    void myReadyRead(); 
    void myReadyReadStandardOutput(); 
}; 

MyProcess::MyProcess(QObject *parent) 
{ 
    connect(this,SIGNAL(readyRead()), 
      this,SLOT(myReadyRead())); 
    connect(this,SIGNAL(readyReadStandardOutput()), 
      this,SLOT(myReadyReadStandardOutput())); 
} 

void MyProcess::myReadyRead() { 
    qDebug() << Q_FUNC_INFO; 
} 

void MyProcess::myReadyReadStandardOutput() { 
    qDebug() << Q_FUNC_INFO; 
    // Note we need to add \n (it's like pressing enter key) 
    this->write(QString("myname" + QString("\n")).toLatin1()); 
    // Next line no required 
    // qDebug() << this->readAll(); 
    qDebug() << this->readAllStandardOutput(); 

} 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    MyProcess *myProcess = new MyProcess(); 

    QString program = "/home/fran/code/myscript.sh"; 

    myProcess->start("/bin/sh", QStringList() << program); 

    a.exec(); 
} 

#include "main.moc" 

Script, um die Anwendung zu testen:

echo "enter your name:" 
read n 
if [ ! -z "$n" ]; 
then 
    echo "success" 
    exit 0; 
else 
    echo "failed" 
    exit 1; 
fi 
+1

Laut der Dokumentation sollte 'QProcess' auch ohne die Event-Schleife funktionieren, also ist' app.exec() 'nicht erforderlich. –

+0

OK. Anyway, in meinem Beispiel ist aufgrund der Signal/Slot-Methoden erforderlich. Danke, @ georgschölly – Tarod

+0

@Tarod Ich war auf der Suche nach der Signal-Slot-Methode, auf dem forum.qt.io wird vorgeschlagen, die Eventloop zu verwenden, obwohl ich mich wohler fühle, die Signal-Slot-Methode für jetzt zu verwenden. Ich werde das testen, ich hoffe wirklich, dass es funktioniert: p – KGCybeX