I'd like to add every line to stdin, but I can't because a.out doesn't exit from loop.
C++ code:
#include <iostream>
int main() {
std::string in;
while(1){
std::cin >> in;
if(in == "exit")
break;
std::cout <<in << "\n";
}
return 0;
}
And a bash code:
#!/bin/bash
while read -r line
do
echo "$line" | ./a.out >> output.txt
done < "input.txt
Thanks!
your C++ part works perfectly. But as soon as it exits, you again do while read -r line. Try to enter EOF just after "exit" line.
Related
I want to use boost-process to read the stdout from a command:
std::string command = "cat /tmp/my_file";
namespace bp = boost::process;
bp::ipstream is;
bp::child c(command, bp::std_out > is);
std::string line;
int no_lines = 0;
while (c.running() && std::getline(is, line) && !line.empty()) {
++no_lines;
}
c.wait();
std::cout << "line count: " << no_lines << "\n";
This is almost identical to the boost-process tutorial.
For testing, the "command" is simply dumping a text file containing 10000 lines.
The problem is my code doesn't read in all the output from the command (for the test case, it only reads in about 9700 lines).
What am I doing wrong?
It seems like the child process is terminating before all of the stdout has been read.
So I am trying to copy a word by word from file1 to file2 , but my code fails in opening file2 (the output file)
void myFile::printWords(string inFile, string outFile)
{
ifstream file;
ofstream file2;
file.open(inFile);
file2.open(outFile);
if (!file.is_open() && !file2.is_open()){
string word;
while (!file.eof()){
file >> word;
file2 << word << '\n';
}
}
else{
cout << "error" << endl;
}
file.close();
file2.close();
}
Any idea why?
Note that you only copy words, if both files failed to open, not if both of them succeeded to open:
if (!file.is_open() && !file2.is_open()){
Replace it with:
if (file.is_open() && file2.is_open()){
if (!file.is_open() && !file2.is_open())
Means if file is not open and file2 is not open. So you will try to read from the files if they are not open and is not you execute cout << "error" << endl;.
Your if condition should be
if (file.is_open() && file2.is_open())
Also if you want to copy one file to another than you can use
file2 << file.rdbuf();
Instead of a while loop.
Problem 1
if (!file.is_open() && !file2.is_open()){
It should be
if (file.is_open() && file2.is_open()){
Problem 2
while (!file.eof()){
file >> word;
file2 << word << '\n';
}
That is wrong. It should be:
while ( file >> word ){
file2 << word << '\n';
}
To understand why, see Why is iostream::eof inside a loop condition considered wrong?.
The tests of the form !file.is_open() shouldn't have the not operator and could be simplified even more by relying on the operator bool() member function. It's also rarely correct to loop on the eof() condition.
Taking those two things in mind I've rewritten your function, I think it's simpler and more correct this way.
void myFile::printWords(const string &inFile, const string &outFile)
{
ifstream file(inFile);
ofstream file2(outFile);
if (file && file2) {
string word;
while (file >> word) {
file2 << word << '\n';
}
} else {
cout << "error" << endl;
}
}
Note: the streams will be closed automatically when they're destroyed at the end of this function.
if (!file.is_open() && !file2.is_open())
if file is not open and file2 is not open
this logic will not copy file to file2 if your testing to see if both files are not open.
I am writing a simple interactive shell program in C++. It should work simalary to sh or bash.
Program looks like this (simplified as much as possible):
#include <iostream>
#include <string>
int main(){
std::string command;
while (1){
std::cout << "prompt> ";
std::getline(std::cin, command);
std::cout << command << std::endl;
if (command.compare("exit") == 0) break;
}
return 0;
}
It works as desired with human interaction. It prompts, user writes command, shell executes it.
However, if I run shell like this ./shell < test.in (redirect input) it produces output with shell prompts like this:
prompt> echo "something"
prompt> echo "something else"
prompt> date
prompt> exit
It does produce correct output (just output input string in this case) but it is 'poluted' with prompts.
Is there some rather simple way to get rid of it (if I do the same with e.g. bash there is no prompt in output) when redirecting input?
Thank you in advance
Assuming you're running on a *NIX-type system, you can (and should) use isatty to test whether stdin is connected to a tty (interactive terminal).
Something like this will work:
if (isatty(STDIN_FILENO)) {
std::cout << "prompt> ";
} // else: no prompt for non-interactive sessions
Solution proposed by cheers-and-hth-alf works for me. Thanks
Solution:
#include <iostream>
#include <string>
#include <unistd.h>
int main(){
std::string command;
while (1){
if (isatty(STDIN_FILENO)){
std::cout << "prompt> ";
}
std::getline(std::cin, command);
std::cout << command << std::endl;
if (command.compare("exit") == 0) break;
}
return 0;
}
Code
while (dataFile)
{
getline(dataFile, input, '$');
if (getenv("windir"))
{
cmd = "open -a 'Google Chrome' http://www.dictionary.reference.com/browse/" + input;
}
else
{
cmd = "open -a 'Safari' http://www.dictionary.reference.com/browse/" + input;
}
system(cmd.c_str());
cmd.erase(cmd.find(input));
cout << cmd;
}
When ever there are more than one words on the .txt file it will only look up the first word and than it can't do the others. It says this in the output sh: line 2: WORD: command not found. How can I get it to reset the command so the other words will work?
Initialization of cmd and input is inside the main method.
string cmd;
string input;
This is how the text file would look like:
Word1
Word2
WordETC
I can't speak for the Safari path, I'm assuming in OSX or similar, but on Windows 7 the following code will open a new tab in Google chrome
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
std::ifstream dataFile("C:\\test.txt", std::ifstream::binary);
string input;
std::string cmd;
// This path will depend on the operation system
std::string googlePath = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
while (dataFile)
{
getline(dataFile, input, '\n'); // use \n for endline
if (getenv("windir"))
{
cmd = "cmd /C start \"" + googlePath + "\" http://www.dictionary.reference.com/browse/" + input + " --newtab";
}
else
{
cmd = "open -a 'Safari' http://www.dictionary.reference.com/browse/" + input;
}
system(cmd.c_str());
cmd.erase(cmd.find(input));
cout << cmd;
}
return 0;
}
test.txt
turtle\r\n
dove\r\n
shoulder
For faster input, I read that you can do file-redirection and include a file with the cin inputs already set.
In theory it should be used like following:
App.exe inputfile outputfile
As far as I understood from C++ Primer book, The following C++ code[1] should be reading cin input from the text file and shouldn't need to any other special indication like[2]
[2]
include <fstream>
ofstream myfile;
myfile.open ();
[1] The following C++ code...
#include <iostream>
int main()
{
int val;
std::cin >> val; //this value should be read automatically for inputfile
std::cout << val;
return 0;
}
Am I missing something?
To use your code [1] you have to call your program like this:
App.exe < inputfile > outputfile
You can also use:
App.exe < inputfile >> outputfile
In this case the output wouldn't be rewritten with every run of the command, but output will be appended to already existing file.
More information about redirecting input and output in Windows you can find here.
Note that the <, > and >> symbols are to be entered verbatim — they are not just for presentation purposes in this explanation. So, for example:
App.exe < file1 >> file2
In addition to original redirection >/ >> and <
You can redirect std::cin and std::cout too.
Like following:
int main()
{
// Save original std::cin, std::cout
std::streambuf *coutbuf = std::cout.rdbuf();
std::streambuf *cinbuf = std::cin.rdbuf();
std::ofstream out("outfile.txt");
std::ifstream in("infile.txt");
//Read from infile.txt using std::cin
std::cin.rdbuf(in.rdbuf());
//Write to outfile.txt through std::cout
std::cout.rdbuf(out.rdbuf());
std::string test;
std::cin >> test; //from infile.txt
std::cout << test << " "; //to outfile.txt
//Restore back.
std::cin.rdbuf(cinbuf);
std::cout.rdbuf(coutbuf);
}
[I am just explaining the command line argument used in Question]
You can provide file name as command line input to the executible, but then you need to open them in your code.
Like
You have supplied two command line arguments namely inputfile & outputfile
[ App.exe inputfile outputfile ]
Now in your code
#include<iostream>
#include<fstream>
#include<string>
int main(int argc, char * argv[])
{
//argv[0] := A.exe
//argv[1] := inputFile
//argv[2] := outputFile
std::ifstream vInFile(argv[1],std::ios::in);
// notice I have given first command line argument as file name
std::ofstream vOutFile(argv[2],std::ios::out | std::ios::app);
// notice I have given second command line argument as file name
if (vInFile.is_open())
{
std::string line;
getline (vInFile,line); //Fixing it as per the comment made by MSalters
while ( vInFile.good() )
{
vOutFile << line << std::endl;
getline (vInFile,line);
}
vInFile.close();
vOutFile.close();
}
else std::cout << "Unable to open file";
return 0;
}
It is important that you understand the concept of redirection. Redirection reroutes standard input, standard output, and standard error.
The common redirection commands are:
> redirects standard output of a command to a file, overwriting previous content.
$ command > file
>> redirects standard output of a command to a file, appending new content to old content.
$ command >> file
< redirects standard input to a command.
$ command < file
| redirects standard output of a command to another command.
$ command | another_command
2> redirects standard error to a file.
$ command 2> file
$ command > out_file 2> error_file
2>&1 redirects stderr to the same file that stdout was redirected to.
$ command > file 2>&1
You can combine redirection:
# redirect input, output and error redirection
$ command < in_file > out_file 2> error_file
# redirect input and output
$ command < in_file > out_file
# redirect input and error
$ command < in_file 2> error_file
# redirect output and error
$ command > out_file 2> error_file
Even though, it is not part of your question, you can also use other commands are powerful when combined with redirection commands:
sort: sorts lines of text alphabetically.
uniq: filters duplicate, adjacent lines of text.
grep: searches for a text pattern and outputs it.
sed : searches for a text pattern, modifies it, and outputs it.