编写一个shell脚本,运行一个程序,模拟用户输入到程序中

时间:2018-03-01 01:47:54

标签: linux shell user-input

我正在尝试编写一个运行可执行C ++程序的shell脚本。 该程序称为预测管理器,打开时允许用户输入 看起来像:

$prg start
$prg pause 
$prg stop 

我编写了一个打开这个预测管理器的shell脚本,但是我希望能够通过shell脚本输入start命令。 我怎么能实现这个?我尝试过使用echo以及yes并将其流水线化到程序中,但我不确定我是否正确执行。 我怎样才能实现这种自动化用户输入

/**  @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;
}
}

1 个答案:

答案 0 :(得分:0)

一个选项是您可以将输入值放在文件中并将其重定向到您的程序,如下所示:

cat InputFileName | YourProgramName

YourProgramName < InputFileName

更新: 看看你的C ++代码,看起来你在你的cout上错过了一个“\ n”(实际上它也可以在没有“\ n”的情况下工作 - 只是在没有“\ n”的输入之后你才会看到提示)

以下代码有效:

#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;
}

使用输入文件myInput.txt:

1
Start
End
exit

以下是我跑步的方式:

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

可替换地:

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