-1

I am trying to write a shell script that runs an executable C++ program. The program is called the prognoser manager and when opened allows user input Looks like:

$prg start
$prg pause 
$prg stop 

I have written a shell script that opens this prognoser manager, however I would like to be able to enter the start command through the shell script. How could I implement this? I have tried using echo as well as yes and pipelining it into the program but I am not sure I am doing it correctly. How could I achieve this automated user input

/**  @file      ProgManager.cpp     Prognostic Manager
*   @class     ProgManager         Prongostic Manager
*   @defgroup  GPIC++    Generic Prognostics Infrastructure-C++
*   @defgroup  Framework Prognostic Framework
*
*   @brief     Main class for C++ Generic Prognostic Infrastructure
*    This class creates the ProgMonitors and Communication Manager.
*
*   @author    Chris Teubert
*   @version   0.1.0
*
*   @pre       Prognostic Configuration File and Prognoster Configuration Files
*
*   @bug       Large delay for ending other threads
*
*      Contact: Chris Teubert (Christopher.a.teubert@nasa.gov)
*      Created: November 11, 2015
*
*   @copyright Copyright (c) 2013-2016 United States Government as represented by
*     the Administrator of the National Aeronautics and Space Administration.
*     All Rights Reserved.
*/

#include <exception>
#include <iostream>
#include <vector>
#include <algorithm>  // For tolower
#include <string>

#include "SharedLib.h"  // for trim
#include "ProgManager.h"
#include "PrognoserFactory.h"
#include "CommManager.h"

namespace PCOE {
    /// CONFIGURABLE PARAMETERS
    const std::string PACKAGE_NAME = "C++ Generic Prognostic Infrastructure";
    const std::string VERSION = "0.1.0";
    const std::string NOTE = "If you have technical issues with the plugin, "
        "please report them by \nemailing Christopher Teubert (christopher.a.teubert@nasa.gov).";
    const std::string MODULE_NAME = "PrognosticManager";
Cmd::Cmd() : command(NONE) {}

class CommonPrognoser;
class CommonCommunicator;

static Log &logger = Log::Instance();

ProgManager::ProgManager() : configValues(), configSet(false) { }

ProgManager::ProgManager(const std::string& path) :
    ProgManager(GSAPConfigMap(path)) { }

ProgManager::ProgManager(const GSAPConfigMap& config)
    : configValues(config), configSet(true) { }

void ProgManager::setConfig(const std::string& path) {
    setConfig(GSAPConfigMap(path));
}

void ProgManager::setConfig(const GSAPConfigMap& config) {
    configValues = config;
    configSet = true;
}

void ProgManager::run() {
    /// Setup Log
    logger.Initialize(PACKAGE_NAME, VERSION, NOTE);
    logger.WriteLine(LOG_INFO, MODULE_NAME, "Enabling");

    CommManager &theComm = CommManager::instance();

    if (!configSet) {
        logger.WriteLine(LOG_DEBUG, MODULE_NAME, "No configuration file set - closing progManager");
        return;
    }

    /// SETUP PROGNOSERS
    logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Setting Up Prognosers");
    std::vector<std::unique_ptr<CommonPrognoser> > prognosers;
    if (configValues.includes("Prognosers")) {
        PrognoserFactory &factory = PrognoserFactory::instance();
        for (auto & itStrs : configValues.at("Prognosers")) {
            prognosers.push_back(factory.Create(itStrs));
            // @todo(CT): Add check that component was made correctly
        }
    }

    /// Setup COMMUNICATION
    // Note: This must be done after the prognosers
    theComm.configure(configValues);
    theComm.start();

    /// Setup Main Loop
    unsigned int counter = 0;
    Cmd ctrl;
    logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Enabled");

    /// Main Loop- Handle controls for prognosers
    while (ctrl.command != STOP) {
        counter++;

        /// Handle Commands
        ctrl = control();

        if (ctrl.command == STOP) {
            logger.WriteLine(LOG_INFO, MODULE_NAME, "Stopping");
            /// STOP PROGNOSERS
            for (auto & prognoser : prognosers) {
                prognoser->stop();
            }
            break;
        }
        else if (ctrl.command == START || ctrl.command == RESUME) {
            logger.WriteLine(LOG_INFO, MODULE_NAME, "Starting");
            /// START PROGNOSERS
            for (auto & prognoser : prognosers) {
                prognoser->start();
            }

            logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Started");

        }
        else if (ctrl.command == PAUSE) {
            logger.WriteLine(LOG_INFO, MODULE_NAME, "Pausing");
            /// PAUSE PROGNOSERS
            for (auto & prognoser : prognosers) {
                prognoser->pause();
            }

            logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Paused");
        }
    }  // End while (command != stop)

    logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Cleanup");

    /// CLEANUP ACTIVITIES
    // End each Prognoser
    for (auto & prognoser : prognosers) {
        logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Waiting for Prognoser thread to stop");
        prognoser->join();// Wait for thread to end
    }

    // Stop Communication Manager
    // NOTE: This has to be done after the other threads that used it are stopped
    theComm.stop();
    logger.WriteLine(LOG_DEBUG, MODULE_NAME, "Waiting for Comm thread to stop");
    theComm.join();

    // Stop Log, exit thread
    logger.WriteLine(LOG_INFO, MODULE_NAME, "Stopped");
    logger.Close();
}

Cmd ProgManager::control() {
    logger.WriteLine(LOG_TRACE, MODULE_NAME, "Waiting for Control Command");

    std::string input;
    Cmd c;

    std::cout << "prg $ ";
    std::cin >> input;  // Receive input
    logger.FormatLine(LOG_TRACE, MODULE_NAME, "Control Command received- %s", input.c_str());
    trim(input);

    if (input.length() == 0) {
        c.command = NONE;
        return c;
    }

    const auto marker = input.find_first_of(" \t");
    std::string command = (input.substr(0, marker));
    std::transform(command.begin(), command.end(), command.begin(), ::tolower);

    // Fill out Command Structure
    if (command.compare("start") == 0) {
        c.command = START;
        logger.WriteLine(LOG_TRACE, MODULE_NAME, "Start command received");
    }
    else if (command.compare("pause") == 0) {
        c.command = PAUSE;
        logger.WriteLine(LOG_TRACE, MODULE_NAME, "Pause command received");
    }
    else if (command.compare("resume") == 0) {
        c.command = RESUME;
        logger.WriteLine(LOG_TRACE, MODULE_NAME, "Resume command received");
    }
    else if (command.compare("stop") == 0) {
        c.command = STOP;
        logger.WriteLine(LOG_TRACE, MODULE_NAME, "Stop command received");
    }
    else {
        c.command = NONE;
        logger.FormatLine(LOG_WARN, MODULE_NAME, "Command not recognized: %s", command.c_str());
    }

    return c;
}
}
Gage Haas
  • 51
  • 1
  • 2
  • 8
  • I have a shell script that opens this prognoser manager program. If i manually type the command "start" and press enter it will start running the program. I need this shell script to input this start command for me. – Gage Haas Mar 01 '18 at 05:50
  • So a simple redirection like `(echo start; sleep 1; echo pause; sleep 1; echo stop ) | ./prog` then. – tripleee Mar 01 '18 at 05:53

1 Answers1

0

One option is you can put the input values in a file and redirect it to your program like so:

cat InputFileName | YourProgramName

or

YourProgramName < InputFileName

UPDATED: Looking at your C++ code, looks like you are missing a "\n" on your cout (Actually it will work without the "\n" also - just that you will see the prompt only after the input without the "\n").

The following code works:

#include <iostream>

int main(int argc, const char * argv[]) {
        std::string input;

    while (input != "exit") {
        std::cout << "prg $ \n";
        std::cin >> input;  // Receive input
        std::cout << "Entered => " + input + "\n";
    }
    return 0;
}

With input file myInput.txt :

1
Start
End
exit

Here is how I ran:

$ ./Test_CPP < myInput.txt
prg $ Entered => 1
prg $ Entered => Start
prg $ Entered => End
prg $ Entered => exit

Alternatively:

$ cat myInput.txt | ./Test_CPP
prg $ Entered => 1
prg $ Entered => Start
prg $ Entered => End
prg $ Entered => exit
Ari Singh
  • 1,228
  • 7
  • 12
  • If this is not working you may have issues with your C++ program - You can post your code of how you are taking the input in your program. – Ari Singh Mar 01 '18 at 02:02
  • after the line ./program I added cat path/to/file/with/start/command | ./program is this the correct way to implement this, it did not start the program – Gage Haas Mar 01 '18 at 02:06
  • the program when opened does not allow the user to enter any commands other than start pause or stop, once stop is entered it exits and normal shell commands will work again. Is this going to prevent the shell script from providing this user input? – Gage Haas Mar 01 '18 at 02:10
  • It looks like your program does not take any user inputs - but it takes parameters. Parameters are different than user inputs. You need to show us the relevant part of your C++ program that takes this user input and/or parameters. – Ari Singh Mar 01 '18 at 02:17
  • I updated it with the code. Thank you for the help – Gage Haas Mar 01 '18 at 02:19
  • *"The relevant part"* not the whole damn thing. Now we have two problems. – tripleee Mar 01 '18 at 03:15
  • Tangentially, you want to avoid recommending the [useless use of `cat`](https://stackoverflow.com/questions/11710552/useless-use-of-cat) – tripleee Mar 01 '18 at 05:36