1

I have the following program (let's call it program.cc):

int main() {
  int x, y, sum;
  std::cout << "A program which adds two integers\n";
  std::cout << "Enter 1st integer: ";
  std::cin >> x;
  std::cout << "Enter 2nd integer: ";
  std::cin >> y;
  sum = x + y;
  std::cout << "Sum is " << sum << std::endl;
  return 0;
}

I'm currently writing a bash script that would take a file and push it through the command line as arguments being passed to this cpp program. As you can see, the above program asks for two inputs.

I know how you can pass the contents of a file for use as input on stdin. But how would you do this if you want to pass the contents of a file as arguments through the command line?

To elaborate, let's say file.txt is the file i'm interested in, which simply contains two integers on separate lines.

EDIT: I tried the xargs command:

       xargs program.cc < file.txt > outputresult.txt

But this ends up printing what I have in cout, e.g.:

     A program which adds two integers
     Enter 1st integer: Enter 2nd integer: Sum is 2

I only want what is cout'ed AFTER all my arguments have been passed. How do I do this?

E 4 6
  • 19
  • Or http://askubuntu.com/q/497159/158442 – muru Sep 29 '15 at 23:00
  • @muru I tried the xargs approach in the links you sent. The file that i save the output of the program to is saving what is being cout'ed in the cpp program. How can I stop that? – E 4 6 Sep 29 '15 at 23:27
  • @E46 What is it you want in the "outputresult.txt"? – AlwaysTalkingAboutMyDog Sep 29 '15 at 23:47
  • @Zzzach..."Sum is x" where x is the sum of the two args – E 4 6 Sep 30 '15 at 00:05
  • you need to check if the input is a tty or not. Use isatty like in http://stackoverflow.com/a/5157076/592540 – Carlos Campderrós Sep 30 '15 at 11:28
  • @muru neither of those is a dupe. xargs is completely unneeded here and there's no need to loop over the output. – terdon Sep 30 '15 at 11:54
  • @terdon "I'm currently writing a bash script that would take a file and push it through the command line as arguments being passed to this cpp program." Think again. – muru Sep 30 '15 at 11:55
  • @muru you think again. There's no need for a bash script, the OP's program can read stdin. None of the linked answers help here, they only make it needlessly complex. Look at what the OP has done in the edit: xargs foo < file when foo <file would do just as well. – terdon Sep 30 '15 at 11:57
  • @terdon For all I know OP intended to modify the program to use arguments instead of reading from stdin. That's what they said. – muru Sep 30 '15 at 11:58
  • @muru that would make it off topic, still not a dupe of a completely unrelated question. As far as I can tell, the OP needed to learn about i) input redirection and ii) the difference between stderr and stdout. Neither of which is really addressed in the dupes as you can tell by the fact that the OP's edit is just a useless use of xargs. – terdon Sep 30 '15 at 12:01
  • @terdon you're supported by an edit that wasn't made when I voted to close. Without the edit, with the program on one hand, and the line I quoted on the other, I was perfectly justified in voting to close. – muru Sep 30 '15 at 12:03
  • @terdon In fact, given the line I quoted, I will still vote to close as a dupe. – muru Sep 30 '15 at 12:05

3 Answers3

2

The way you have written it, you need to pass the contents of the file to your program, not the file itself (and there's no need for xargs, by the way). One way to do that is using input redirection:

a.out < file

For example:

$ cat file
4 
7
$ ./a.out < file
A program which adds two integers
Enter 1st integer: Enter 2nd integer: Sum is 11

Another way to do the same thing is to print the file's contents and pass the to your program with a pipe:

$ cat file | ./a.out 
A program which adds two integers
Enter 1st integer: Enter 2nd integer: Sum is 11

A much cleaner approach, of course, would be to write your program so that it can take arguments instead of reading standard input:

./a.out 4 7

Or, write it so that it can open files internally and parse them for its input data:

./a.out file

Anyway, in order to get only the last line in the output, print the rest to standard error:

#include <iostream>

int main() {
  int x, y, sum;
  std::cerr << "A program which adds two integers\n";
  std::cerr << "Enter 1st integer: ";
  std::cin >> x;
  std::cerr << "Enter 2nd integer: ";
  std::cin >> y;
  std::cerr << "\n";
  sum = x + y;
  std::cout << "Sum is " << sum << std::endl;
  return 0;
}

Now, run:

$ ./a.out < file > output.txt
A program which adds two integers
Enter 1st integer: Enter 2nd integer: 
$ cat output.txt
Sum is 11

Or, to give the values manually:

$ ./a.out > output.txt 
A program which adds two integers
Enter 1st integer: 4
Enter 2nd integer: 7

$ cat output.txt 
Sum is 11
terdon
  • 100,812
  • Great answer! Why does whatever you give to cerr stream not get printed? Does it have anything to do with std::cerr << '\n'? How does it work? – daltonfury42 Sep 30 '15 at 11:48
  • 1
    @daltonfury42 it is printed but to standard error, not standard output. > file only redirects standard output and not standard error. That's why you can see the cerr lines in the terminal but not in the output file. The std::cerr << '\n' is just to print a newline to make the output look correct. – terdon Sep 30 '15 at 11:52
1

As terdon pointed out already, to do this you want to either redirect stdin from a file (and call the program using e.g. program <inputfile.txt) or change your program so that it parses arguments passed from the command line (and call the program using e.g. program 1 2);

In the first case you want to suppress the first two couts if stdin is not connected to a terminal, and in the second case you want to suppress the first two couts, e.g., if, say, not enough arguments have been passed from the command line;

Speaking of the first method, you can check whether a file descriptor is connected to a terminal using the isatty() function (POSIX function defined in unistd.h):

int isatty(int fd);

If fd is an opened file descriptor connected to a terminal, the function will return 1; If fd is not an opened file descriptor or is not connected to a terminal, the function will return 0:

#include <iostream>
#include <unistd.h>

int main() {
    int x, y, sum;
    std::cout << "A program which adds two integers\n";
    if(isatty(0)) {
        std::cout << "Enter 1st integer: ";
    }
    std::cin >> x;
    if(isatty(0)) {
        std::cout << "Enter 2nd integer: ";
    }
    std::cin >> y;
    sum = x + y;
    std::cout << "Sum is " << sum << std::endl;
    return 0;
}

This way the user will be prompted to insert the numbers only if stdin has not been redirected:

user@user-X550CL ~/tmp % ./a.out               
A program which adds two integers
Enter 1st integer: 1
Enter 2nd integer: 2
Sum is 3
user@user-X550CL ~/tmp % cat inputfile.txt 
3
4
user@user-X550CL ~/tmp % ./a.out <inputfile.txt 
A program which adds two integers
Sum is 7

Speaking of the second method, here's a very rough example on how to parse arguments passed from the command line (arguments passed from the command line are stored into argv, which is an array of pointers to a character, so you'll have to cast each argument to an integer, but don't use atoi()! Use something that allows you to check if the arguments are numeric or not. I used atoi() just for the sake of simplicity):

#include <iostream>
#include <cstdlib>

int main(int argc, char *argv[]) {
    int x, y, sum;
    std::cout << "A program which adds two integers\n";
    if(argc == 3) {
        x = atoi(argv[1]);
        y = atoi(argv[2]);
    }
    else {
        std::cout << "Enter 1st integer: ";
        std::cin >> x;
        std::cout << "Enter 2nd integer: ";
        std::cin >> y;
    }
    sum = x + y;
    std::cout << "Sum is " << sum << std::endl;
    return 0;
}

This way the user will be prompted to insert the numbers only if not enough arguments have been passed from the command line:

user@user-X550CL ~/tmp % ./a.out
A program which adds two integers      
Enter 1st integer: 1
Enter 2nd integer: 2
Sum is 3
user@user-X550CL ~/tmp % ./a.out 3
A program which adds two integers
Enter 1st integer: ^C
user@user-X550CL ~/tmp % ./a.out 3 4
A program which adds two integers
Sum is 7
kos
  • 35,891
0

So there are a few things you can do:

  1. You can output to file within C++ using something like this.
  2. You can remove the cout << "Enter... lines in your code so the only output of the program is what goes into the file.
  3. You can work around using the error output stream (cerr instead of cout) and manipulate the outputs accordingly. If you want cout visible and cerr in the file, do xargs program.cc < file.txt 2> outputresult.txt (using 2> instead of >). If you want cerr visible and cout in the file, do it as you had it above with just >.
  4. Keep the output as it is now, but run 2 more executions that removes the unwanted lines from your code:

cat outputresult.txt | grep Sum > tempfile && mv tempfile outputresult.txt

You can implement this with your code like this:

./program.cc < file.txt | grep Sum > outputresult.txt

This method requires newlines to be written, however, so you'd have to make sure that the output it each in new lines.

I would personally suggest using either the file management within C++ or the cout and cerr hack, depending on the use of the program.

AlwaysTalkingAboutMyDog
  • 3,783
  • 2
  • 25
  • 38
  • Why use xargs? It doesn't do anything useful here. Also, there's no need for a temp file if you want to parse the output: program.cc < file | grep Sum > output will do it. – terdon Sep 30 '15 at 11:31
  • True, but I was going off of the commands the OP was specifying above. I'll add the shorter version. And yea, xargs isn't needed, but again, it was what the OP was initially using. – AlwaysTalkingAboutMyDog Oct 01 '15 at 17:38