Passing contents of file as argument into C++ program - c++

Using C++, need to pass the contents of a file to the program as an argument à la $ ./main <filename.txt or $ echo the contents of the file | ./main
I want to be able to access the contents of the file as a variable or something so I can manipulate further.
I have this basic listing including some of the stuff I've been trying. The data doesn't seem to be in argv (my runs always tell me I have one argument). What is the way to access a command line argument passed in this way?
#include <fstream>
#include <iostream>
int main(int argc, char **argv)
{
std::cout << "Have " << argc << " arguments:" << std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
std::istream* input = &std::cin;
if(argc > 1) {
std::cout << input;
std::cout << "more than argument found\n";
}
std::string inputs;
std::cout<< "1:\n";
std::cout<< argv[0];
std::cout<< "\n2:\n";
std::cout<< argv[1];
std::cout<< "\n3:\n";
std::cout<< input;
std::cout<< "\nEnd\n";
return 0;
}
EDIT
I perhaps wasn't entirely clear, given it was a fairly fundamental question I was asking but didn't realize. Essentially, passing using $ ./main <filename.txt is non-negotiable. User RPGillespie's comment pointed me in the right direction. The pipe sends it to stdin (which I didn't realize). Thus I wanted to handle the data using cin. A minimal working example would be
int main() {
// read input
for (std::string line; std::getline(std::cin, line);) {
std::cout << line << std::endl;
}
return 0;
}

cat file | ./main will pipe the file content to the input of the ./main, not the argument.
If you want to pipe arguments in this way, use xargs:
cat file | xargs ./main

While #liliscent has a great solution, the following also works (I am mentioning it for the sake of completeness and since I feel it is more readable):
./main $(cat file)
This takes the contents of the file called file (since it interprets the command inside the $( and )), and passes them as arguments to ./main.

Related

Taking a filename as an input while running a program I compiled in cpp

In cpp, I need to run a program like this
g++ *.cpp -o out
./out <input.txt> <somenumber>
where input.txt is a text file containing lines of information I need to proccess, and somenumber is an integer value I need to use.
I am searching for hours and couldn't find the answer I was looking for,
I found solutions that work like
./out < input.txt
reads the input.txt line as a string which then in the code I can process,
but the assignment says that the code will be run only and specifically as
./out <input.txt> <somenumber>
can anyone help ?
I have wrote some code, in which I wrote my main as
int main(int argc, char* argv[] ){
but when I run
./out <input.txt>
the terminal gives an error saying
" -bash: syntax error near unexpected token `newline' "
edit: typo
You are correct in wanting to accomplish this using argc and argv. Something like this should work
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
std::string file_name;
std::string number;
if(argc == 3) {
file_name = argv[1];
number = argv[2];
}
std::cout << "Filename: " << file_name << " number: " << number << "\n";
}
By convention, the use of < > to enclose an input parameter signifies that the parameter is mandatory for the command.
Therefore, the command
./out <input.txt> <some_number>
signifies that the two parameters - input.txt and some_number are mandatory.
The command can be run as:
./out input.txt 101
Here is an example of working code:
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
string inputFile;
string someNumber;
if(argc != 3) {
cout << "Sorry! Wrong input \n";
cout << "Usage: ./out <input_file_name> <some_number> \n";
return -1;
}
inputFile = argv[1];
someNumber = argv[2];
cout << "Processing ...\n";
cout << "File = " << inputFile << ", Number = " << someNumber << "\n";
return 0;
}
Output:
$ ./out input.txt 101
Processing ...
File = input.txt, Number = 101

Recieve 3 files by terminal and concatenate the content of file2 and file3 to file1 using fstream

I'm begginer in C++, so may be parts of my code doesn't have sense, sorry.
What I have to do is (C++, Linux, by fstream):
· Receive 3 or more files passed by terminal by:
./executable file1.txt file2.txt file3.txt
· programm a function that read the files file2.txt and file3.txt and copy it to file1.txt (concatenate, don't overwrite)
I don't know how to do it, I don't know anything about fstream, I'm just learning now by myself, so I really need help. Maybe there are similar questions solved in SO, but I don't know how to solve my problem by them.
I attach the code I have. I don't know how to code the function, so it's empty.
Thank you so much.
I try doing:
void concat(char *argv[], int numberoffilesreceived){
char c;
towritethefiles.open(argv[0], ios::app);
for(int i=1; i<numberoffilesreceived; i++){
toreadthefiles.open(argv[i], ios::in);
while(!toreadthefiles.eof()){
toreadthefiles >> c;
towritethefiles<< c;
}
}
}
It compiles but doesn't work, the program freezes when you run it.
and I also try using std::copy by I don't understand how it works.
ifstream toreadthefiles;
ofstream towritethefiles;
void concat(char *argv[], int numberoffilesreceived);
int main(int argc, char *argv[]){
/* 1/2 The code from below to 2/2 it's only to prevent path errors when receiving the files (it works fine) */
const char directory[SIZE]="./";
int count_files=0;
char files[SIZE][SIZE];
for(int i=1; i<argc; i++){
strcpy(files[i], directory);
strcat(files[i], argv[i]);
count_files++;
}
/*2/2 to add ./ to the name files when passed by terminal: ./executable ./file1.txt ./file2.txt ./file3.txt */
/*check if received almost 3 files like required */
if(argc<3){
cout<< "Error, to few files entered" << endl;
getchar();
exit(1);
}
/*pass the files to the concat function*/
for(int i=1; i<argc; i++){
concat(&argv[i], count_files);
}
toreadthefiles.close();
towritethefiles.close();
return 0;
}
void concat(char *argv[], int count_files){
}
I think I see an issue with your concat() function. You are calling concat() for each of the files passed in. Then in the function, you are using count_files to run that loop again for the number of files passed in.
I would consider rewriting concat() function so that it looks like this:
void concat(std::ofstream& outputStream, char* fileToAppend)
{
std::ifstream in(fileToAppend);
if (!in) {
cout << "Error, cannot open file: " << fileToAppend;
return;
}
// Use std::getline to read each line in the input stream,
// then write it to the output stream!
string line;
while (std::getline(in, line)) {
outputStream << line;
}
}
The benefit being that you can reuse the function for appending a single input file to an existing output stream, and you wrap up the check to ensure the file exists (you may want something more sophisticated like returning true/false on the file being appended, or throwing an error, etc.).
In main(), you would replace the code after the check for at least three files with something like:
// Create an output stream with the first file
// ios::out- output flag
// ios::app- append flag
std::ofstream out(argv[1], ios::out | ios::app);
// Make sure the file exists!
if (!out) {
cout << "Error, cannot open file: " << argv[1];
exit(1);
}
// For all other arguments, concat with the first.
for (int i = 2; i < argc; i++) {
concat(out, argv[i]);
}
You can use std::copy with stream iterators, and I've revised my previous suspicion that it would be slow, so here's one way using doing just that with comments in the code.
#include <iostream>
#include <fstream>
#include <vector>
#include <ios>
#include <stdexcept>
void concat(const std::string& destination, const std::vector<std::string>& sources) {
// open the destination file and keep it open until all is done
std::ofstream dest_fs(destination, std::ios_base::binary);
if(!dest_fs)
throw std::runtime_error("Could not write to \"" + destination + "\".");
// loop over the source files
for(const auto& source_file : sources) {
// open the current source file
std::ifstream source_fs(source_file, std::ios_base::binary);
if(!source_fs)
throw std::runtime_error("Could not read from \"" + source_file + "\".");
// copy from source to destination
std::copy(std::istreambuf_iterator<char>(source_fs),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(dest_fs));
}
}
int cppmain(std::string program, std::vector<std::string> args) {
if(args.size() < 2) {
std::cout << "USAGE: " << program << " destination_file input_file(s)\n";
return 1;
}
// extract the first argument which is the destination file
std::string destination_file = std::move(args.front());
args.erase(args.begin()); // erase first argument from the vector
try {
// do the concatenation
concat(destination_file, args);
return 0;
} catch(const std::exception& ex) {
std::cerr << program << ": ERROR: " << ex.what() << "\n";
return 1;
}
}
int main(int argc, char* argv[]) {
return cppmain(argv[0], {argv + 1, argv + argc});
}

'Continuous' C++ output of one executable as Input to another program

I am trying to pass the output generated by one executable as input into another. I have been able to send in one line at a time.
The problem is when I try to send in a 'sequence of lines generated in a while loop' from Program1 to be read as input by Program2. I tried piping the executables in terminal (as given below), but it fails to work.
./Program1 | ./Program2
./Program1 |xargs ./Program2
./Program1 > ./Program2
I want to avoid File I/O.
Note:
Platform : Linux
==================
Something along the lines of the following example
Program1 (Writing to Terminal)
int main(int argc, char *argv[])
{
int i = 2200;
while(1){
printf("%d \n", i);
i++;
}
}
Program2 (Reading from Terminal, the output of Program1)
int main(int argc, char *argv[])
{
while(1){
// Read 'i' values
cout << "There are " << argc << " arguments:" << endl;
// Loop through each argument and print its number and value
for (int nArg=0; nArg < argc; nArg++)
cout << nArg << " " << argv[nArg] << endl;
}
return 0;
}
The problem is that you are trying to read the program arguments. But when you pipe from one program to the next the output from the first program becomes the standard input (std::cin) of the second program.
Try this for program 2:
#include <string>
#include <iostream>
int main()
{
std::string line;
while(std::getline(std::cin, line)) // read from std::cin
{
// show that it arrived
std::cout << "Line Received: " << line << '\n';
}
}

is it possible to grab data from an .exe file in c++?

I am new at C/C++,
So basically I want to call an .exe file that displays 2 numbers and be able to grab those two numbers to use them in my code.
To call the .exe file I've used the system command, but I am still not able to grab those two numbers that are displayed by the .exe file
char *files = "MyPath\file.exe";
system (files);
I think this is better aproach:
Here you just create new process, and you read data that process gives you. I tested this on OS X 10.11 with .sh file and works like a charm. I think that this would probably work on Windows also.
FILE *fp = popen("path to exe","r");
if (fp == NULL)
{
std::cout << "Popen is null" << std::endl;
}else
{
char buff[100];
while ( fgets( buff, sizeof(buff), fp ) != NULL )
{
std::cout << buff;
}
}
You need to escapr back slashes in C++ string literals so:
// note the double "\\"
char* files = "MyPath\\file.exe";
Or just use forward slashes:
char* files = "MyPath/file.exe";
Its not very efficient but one thing you can to with std::system is redirect the output to a file and then read the file:
#include <cstdlib>
#include <fstream>
#include <iostream>
int main()
{
// redirect > the output to a file called output.txt
if(std::system("MyPath\\file.exe > output.txt") != 0)
{
std::cerr << "ERROR: calling system\n";
return 1; // error code
}
// open a file to the output data
std::ifstream ifs("output.txt");
if(!ifs.is_open())
{
std::cerr << "ERROR: opening output file\n";
return 1; // error code
}
int num1, num2;
if(!(ifs >> num1 >> num2))
{
std::cerr << "ERROR: reading numbers\n";
return 1; // error code
}
// do something with the numbers here
std::cout << "num1: " << num1 << '\n';
std::cout << "num2: " << num2 << '\n';
}
NOTE: (thnx #VermillionAzure)
Note that system doesn't always work everywhere because unicorn
environments. Also, shells can differ from each other, like cmd.exe
and bash. – VermillionAzure
When using std::system the results are platform dependant and not all shells will have redirection or use the same syntax or even exist!

Variable length and position command line arguments

So, quick question:
I am tasked with making a program that reads in a file, does some fancy things, and writes out to an html file with the re-purposed text, all simple stuff.
Furthermore the program must be able to accept up to four command line arguments (but a minumum of two). The executable of course, the file it is reading in, the file name it will be reading out to, and finally a "-r" argument for more information on the file (the amount of paragraphs, etc).
So the question I have is as follows:
the "-r" argument can be anywhere in the arguments (as long as it comes after argv[0] of course), or it can be completely non-existent (as can the output file name).
This is still simple to do, a little tedious writing a bunch of if's or even a switch or two, but I can't help but think that there may be an easier way to accomplish this, rather than having a plethora of if statements.
Any help would be greatly appreciated. (I also suppose you don't need any code considering I don't exactly have a problem.)
Here is roughly how one might do it without a library:
GCC 4.8.2: g++ -Wall -Wextra -std=c++0x main.cpp
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
char* input = nullptr;
char* output = nullptr;
char* r_arg = nullptr;
--argc; ++argv; // Skip the program name.
const char* def_in = "default in";
const char* def_out = "default out";
const char* def_r = "default r";
while (0 < argc) {
if (std::string(argv[0]) == "-r") {
// This code requires a space after the "-r", which is unusual.
++argv;
--argc;
r_arg = argv[0]; }
else if (input == nullptr) {
input = argv[0]; }
else if (output == nullptr) {
output = argv[0]; }
else {
std::cerr << "error: unexpected arg '" << argv[0] << "'\n"; }
++argv;
--argc; }
if (input == nullptr) {
input = const_cast<char*>(def_in); }
if (output == nullptr) {
output = const_cast<char*>(def_out); }
if (r_arg == nullptr) {
r_arg = const_cast<char*>(def_r); }
std::cout << "input: " << input << "\n"
<< "output: " << output << "\n"
<< "r arg: " << r_arg << "\n";
return 0; }