2013-02-13 41 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