2013-02-13 31 views
2

我有一个C++可执行的是,在正常使用中,接受文件名作为以下面的方式的参数的选项:访问在C++通过bash进程取代创建的“虚拟文件”

executable -i myFile.txt 

欲使用击进程替换以下面的方式来创建一个“虚拟文件”,并发送信息(简单,通过行数据线)到这个可执行:

executable -i <(echo "${myData}") 

然而,我的C++程序没有在访问所述信息,当我使用这个过程替代。在C++程序代码的主要文件读取部分如下:

ifstream file1 (fileName1); 
string line; 
int currentLineNumber = 0; 
if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;} 
while (getline (file1, line)){ 
    currentLineNumber++; 
    if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";} 
    istringstream linestream(line); 
    string item; 
    int itemNumber = 0; 
    while (getline (linestream, item, ',')){ 
     itemNumber++; 
     if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";} 
     // data 
      if (itemNumber == 1) {x[currentLineNumber]=atof(item.c_str());} 
      if (itemNumber == 2) {y[currentLineNumber]=atof(item.c_str());} 
    } 
} 
file1.close(); 

你能指出我对解决这个问题的阅读方向是正确的?是否有更好的方法可以用于正常文件读取和进程替换“文件”读取?

我是新来的这个过程替代,我非常感谢这方面的帮助。


编辑:

以下一些意见,接下来是说明我遇到的问题最小工作示例:

// definition of standard input/output stream objects 
    #include <iostream> 
// manipulate strings as though they were input/output streams 
    #include <sstream> 
// input and output operations 
    #include <stdio.h> 
// file input and output operations 
    #include <fstream> 
// manipulate C strings and arrays 
    #include <string.h> 
// classify and transform individual characters 
    #include <ctype.h> 
// Standard General Utilities Library 
    #include <stdlib.h> 
// getopts (handle command line options and arguments) 
    #include <unistd.h> 
// sstream (handle conversion from char* to double) 
    #include <sstream> 

using namespace std; 

double returnDoubleFromPointerToChar(const char *cText){ 
    std::stringstream ss (cText); 
    double dText = 0; 
    ss >> dText; 
    return dText; 
} 

int returnNumberOfLinesInFile(const char *fileName1){ 
    int lineCount = 0; 
    string line; 
    ifstream file1(fileName1); 
    while (std::getline(file1, line)) 
     ++lineCount; 
    file1.close(); 
    return lineCount; 
} 

int main (int argc, char **argv){ 
    char *fileName1 = NULL; // input file name (i) (required input) 
    int verboseFlag = 0;  // verbose flag  (v) 
    int index; // internal variable 
    int c; // internal variable 
    opterr = 0; 

    // process command line arguments and options 
     while ((c = getopt (argc, argv, "i:v")) != -1) 
      switch (c){ 
       case 'i': 
        fileName1 = optarg; 
        break; 
       case 'v': 
        verboseFlag = 1; 
        break; 
       case '?': 
        if (
         optopt == 'i' 
        ){ 
         fprintf (stderr, "option -%c requires an argument.\n", optopt); 
        } 
        else if (isprint (optopt)){ 
         fprintf (stderr, "unknown option `-%c'.\n", optopt); 
        } 
        else { 
         fprintf (stderr, "unknown option character `\\x%x'.\n", optopt); 
        } 
        return 1; 
       default: 
        abort(); 
     } 
     for (index = optind; index < argc; index++) printf ("non option argument %s\n", argv[index]); 
    if (verboseFlag == 1){ 
     cout << endl; 
     cout << "input file name: " << fileName1 << endl; 
    } 
    // Determine the number of lines in the input file. 
     int numberOfLinesInInputFile=returnNumberOfLinesInFile(fileName1); 
     if (verboseFlag == 1) {cout << "number of lines in input file: " << numberOfLinesInInputFile << endl;} 
    // number of data points 
     int n=numberOfLinesInInputFile-1; 
    // x variable 
     double x[n]; 
    // y variable 
     double y[n]; 
    // Access the data in the input file. 
     ifstream file1 (fileName1); 
     string line; 
     int currentLineNumber = 0; 
     if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;} 
     while (getline (file1, line)){ 
      currentLineNumber++; 
      if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";} 
      istringstream linestream(line); 
      string item; 
      int itemNumber = 0; 
      while (getline (linestream, item, ',')){ 
       itemNumber++; 
       if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";} 
       // data 
        if (itemNumber == 1) {x[currentLineNumber]=atof(item.c_str());} 
        if (itemNumber == 2) {y[currentLineNumber]=atof(item.c_str());} 
      } 
      if (verboseFlag == 1) {cout << endl;} 
     } 
     file1.close(); 
    return 0; 
} 

编辑:

我已经添加了解决方案代码下面(来自其他人的评论):

// include WBM C++ library 
// #include "lib_cpp.c" 
// definition of standard input/output stream objects 
    #include <iostream> 
// manipulate strings as though they were input/output streams 
    #include <sstream> 
// input and output operations 
    #include <stdio.h> 
// file input and output operations 
    #include <fstream> 
// manipulate C strings and arrays 
    #include <string.h> 
// classify and transform individual characters 
    #include <ctype.h> 
// Standard General Utilities Library 
    #include <stdlib.h> 
// getopts (handle command line options and arguments) 
    #include <unistd.h> 
// sstream (handle conversion from char* to double) 
    #include <sstream> 

using namespace std; 

// example usage: 
// ./graph2d -i data.txt -o data.eps -v 
// ./graph2d -i data.txt -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -v 
// ./graph2d -i data.txt -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -a 70 -b 50 -c 22 -d 7 -v 
// ./graph2d -i <(echo "${dataForTrainingErrorVersusEpoch}") -o graph.eps -t "training test error versus epochs" -x "epochs" -y "error measure" -v 

double returnDoubleFromPointerToChar(const char *cText){ 
    std::stringstream ss (cText); 
    double dText = 0; 
    ss >> dText; 
    return dText; 
} 

int main (int argc, char **argv){ 
    char *fileName1 = NULL; // input file name (i) (required input) 
    char *fileName2 = NULL; // output file name (o) (required input) 
    char *graphTitleMain = NULL; // graph title  (t) 
    char *graphTitleAxisx = NULL; // graph x axis title (x) 
    char *graphTitleAxisy = NULL; // graph y axis title (y) 
    double axisyMaximum = DBL_MAX; // y axis maximum (a) 
    double axisyMinimum = DBL_MAX; // y axis minimum (b) 
    double axisxMaximum = DBL_MAX; // x axis maximum (c) 
    double axisxMinimum = DBL_MAX; // x axis minimum (d) 
    int verboseFlag = 0;  // verbose flag  (v) 
    int index; // internal variable 
    int c; // internal variable 
    opterr = 0; 

    // process command line arguments and options 
     while ((c = getopt (argc, argv, "i:o:t:x:y:a:b:c:d:v")) != -1) 
      switch (c){ 
       case 'i': 
        fileName1 = optarg; 
        break; 
       case 'o': 
        fileName2 = optarg; 
        break; 
       case 't': 
        graphTitleMain = optarg; 
        break; 
       case 'x': 
        graphTitleAxisx = optarg; 
        break; 
       case 'y': 
        graphTitleAxisy = optarg; 
        break; 
       case 'a': 
        axisyMaximum = returnDoubleFromPointerToChar(optarg); 
        break; 
       case 'b': 
        axisyMinimum = returnDoubleFromPointerToChar(optarg); 
        break; 
       case 'c': 
        axisxMaximum = returnDoubleFromPointerToChar(optarg); 
        break; 
       case 'd': 
        axisxMinimum = returnDoubleFromPointerToChar(optarg); 
        break; 
       case 'v': 
        verboseFlag = 1; 
        break; 
       case '?': 
        if (
         optopt == 'i' || 
         optopt == 'o' || 
         optopt == 't' || 
         optopt == 'x' || 
         optopt == 'y' || 
         optopt == 'a' || 
         optopt == 'b' || 
         optopt == 'c' || 
         optopt == 'd' 
        ){ 
         fprintf (stderr, "option -%c requires an argument.\n", optopt); 
        } 
        else if (isprint (optopt)){ 
         fprintf (stderr, "unknown option `-%c'.\n", optopt); 
        } 
        else { 
         fprintf (stderr, "unknown option character `\\x%x'.\n", optopt); 
        } 
        return 1; 
       default: 
        abort(); 
     } 
     for (index = optind; index < argc; index++) printf ("non option argument %s\n", argv[index]); 
    if (verboseFlag == 1){ 
     cout << endl; 
     cout << "input file name: " << fileName1 << endl; 
     cout << "output file name: " << fileName2 << endl; 
    } 
    // x variable 
     vector<int> x; 
    // y variable 
     vector<int> y; 
    // Access the data in the input file. 
     ifstream file1 (fileName1); 
     string line; 
     int currentLineNumber = 0; 
     if (verboseFlag == 1) {cout << "reading data from file " << fileName1 << "..." << endl;} 
     while (getline (file1, line)){ 
      currentLineNumber++; 
      if (verboseFlag == 1) {cout << "line " << currentLineNumber << ": ";} 
      istringstream linestream(line); 
      string item; 
      int itemNumber = 0; 
      while (getline (linestream, item, ',')){ 
       itemNumber++; 
       if (verboseFlag == 1) {cout << "item " << itemNumber << ": " << item << " ";} 
       // data 
        if (itemNumber == 1) {x.push_back(atof(item.c_str()));} 
        if (itemNumber == 2) {y.push_back(atof(item.c_str()));} 
      } 
      if (verboseFlag == 1) {cout << endl;} 
     } 
     file1.close(); 
     int numberOfLinesInInputFile = currentLineNumber + 1; 
    // number of data points 
     int n=numberOfLinesInInputFile; 
    // graph 
     if (verboseFlag == 1){ 
      cout << "graph main title: " << graphTitleMain << endl; 
      cout << "graph x axis title: " << graphTitleAxisx << endl; 
      cout << "graph y axis title: " << graphTitleAxisy << endl; 
     } 
     // Create a new canvas. 
      TCanvas *c1 = new TCanvas(graphTitleMain, graphTitleMain); // #u 
     // Create a new graph. 
      //TGraph *graph = new TGraph(n, x, y); 
      TGraph *graph = new TGraph(n, &x[0], &y[0]); 
     // Set the graph titles. 
      graph->SetTitle(graphTitleMain); 
      graph->GetXaxis()->SetTitle(graphTitleAxisx); 
      graph->GetYaxis()->SetTitle(graphTitleAxisy); 
     // Set the marker styles. 
      graph->SetMarkerColor(2); // red 
      graph->SetMarkerStyle(kFullCircle); // circle 
      graph->SetMarkerSize(1); // default size 
     // Set the graph range, if ranges have been specified in command line options. 
      if (
       axisyMaximum != DBL_MAX && 
       axisyMinimum != DBL_MAX 
      ){ 
       if (verboseFlag == 1){ 
        cout << "graph y axis minimum: " << axisyMinimum << endl; 
        cout << "graph y axis maximum: " << axisyMaximum << endl; 
       } 
       graph->GetYaxis()->SetRangeUser(axisyMinimum, axisyMaximum); 
      } 
      if (
       axisxMaximum != DBL_MAX && 
       axisxMinimum != DBL_MAX 
      ){ 
       if (verboseFlag == 1){ 
        cout << "graph x axis minimum: " << axisxMinimum << endl; 
        cout << "graph x axis maximum: " << axisxMaximum << endl; 
       } 
       graph->GetXaxis()->SetRangeUser(axisxMinimum, axisxMaximum); 
      } 
     // Draw the canvas, then draw the graph and then save the canvas to an image file. 
      c1->Draw(); 
      graph->Draw("ALP"); 
      // disable ROOT messages 
       gErrorIgnoreLevel = 5000; 
      if (verboseFlag == 1) {cout << "saving file " << fileName2 << "..." << endl;} 
      c1->SaveAs(fileName2); 
    if (verboseFlag == 1) {cout << endl;} 
    return 0; 
} 
+0

你读什么过程?也许它在检测到输出不输出到tty时缓冲输出。 – 2013-02-13 21:16:56

+0

那么当你将'verboseFlag'设置为非零时,你的程序产生了什么输出。 – JoergB 2013-02-13 21:19:46

+0

黑暗猎鹰,我正在从存储简单的ASCII数据(两列CSV数字数据)的Bash变量中读取数据。 JoergB,该程序将输入信息输入到数组中,并将这些数组用于绘图。绘图方面或程序将从我添加的最小工作示例中删除,因为如果详细打印输出有效,它应该可以工作。 – d3pd 2013-02-13 21:51:57

回答

3

首先,我裁减了三分之二的程序,但仍然显示出问题。这是非常接近最小值:

#include <iostream> 
#include <fstream> 

using namespace std; 

int returnNumberOfLinesInFile(const char *fileName1){ 
    int lineCount = 0; 
    string line; 
    ifstream file1(fileName1); 
    while (std::getline(file1, line)) 
    ++lineCount; 
    file1.close(); 
    return lineCount; 
} 

int main (int argc, char **argv){ 
    char *fileName1 = argv[1]; 
    cout << "input file name: " << fileName1 << endl; 
    int numberOfLinesInInputFile=returnNumberOfLinesInFile(fileName1); 
    cout << "number of lines in input file: " << numberOfLinesInInputFile << endl; 

    ifstream file1(fileName1); 
    string line; 
    cout << "File contents: " << endl; 
    while (getline (file1, line)){ 
    cout << "line: " << line << endl; 
    } 
    file1.close(); 
    return 0; 
} 

这里的问题是,您打开文件两次。 <(process substitution)只运行一次命令并传输结果。如果你想再次读取输出,Bash不会再自由地运行命令,因为除了吐出文本之外,命令本来可以做很多其他的事情。

确保您的程序只打开并读取一次内容,并且它会工作。这可能会要求你稍微重写一下你的逻辑,或者只是懒惰,一次将它全部读入内存。

+0

啊,这就是问题所在!非常感谢你的协助!我很抱歉没有缩短代码插图(我已经删除了很多代码,并且对于我偏颇的眼睛来说似乎很短)。我修改了我的代码,以便使用向量而不是数组来存储数据,并根据需要将新数据推回到向量中。为了容纳一个ROOT TGraph对象,数组被初始使用,但是在创建TGraph对象时,我使用了&x [0]技巧,其中x是一个向量。 – d3pd 2013-02-13 23:40:08

0

你的代码对我来说工作得很好(我在OS X上)。请注意,与真实文件不同,“虚拟文件”通常是管道端点(使用文件描述符专用文件在bash中实现)。所以,你不能多次打开,阅读和关闭一个虚拟文件,否则第二次你什么也得不到。

+0

除非在zsh中使用'=(...)'(方便知道)。从['man zshexpn'](http://linux.die.net/man/1/zshexpn):如果使用'=(...)'代替'<(...)',那么文件作为参数传递将是包含列表进程的输出的临时文件的名称。这可以用来代替输入文件中需要lseek(参见lseek(2))的程序的<<形式。 – unthought 2013-02-13 21:35:47