I am trying to pass a command into my shell script via a C++ program, but I am not familiar with C++ at all and, while I know that I must use system(), I am not sure how to set it up effectively.
#include <iostream>
#include <stdlib.h>
int main() {
system("./script $1");
return 0;
}
This is what I currently have.
It seems that I can't use positional parameters in the system command, but I wasn't sure what else to do. I'm trying to pass in an argument to the script via the C++ program.
If you just want to call "./script" with the first argument to the C++ program passed as the first argument to the script, you could do it like this:
#include <iostream>
#include <string>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if (argc < 2)
{
printf("Usage: ./MyProgram the_argument\n");
exit(10);
}
std::string commandLine = "./script ";
commandLine += argv[1];
std::cout << "Executing command: " << commandLine << std::endl;
system(commandLine.c_str());
return 0;
}
Properly executing a shell command from C++ actually takes quite a bit of setup, and understanding exactly how it works requires a lot of explanation about operating systems and how they handle processes. If you want to understand it better, I recommend reading the man pages on the fork() and exec() commands.
For the purposes of just executing a shell process from a C++ program, you will want to do something like so:
#include <unistd.h>
#include <iostream>
int main() {
int pid = fork();
if (pid == 0) {
/*
* A return value of 0 means this is the child process that we will use
* to execute the shell command.
*/
execl("/path/to/bash/binary", "bash", "args", "to", "pass", "in");
}
/*
* If execution reaches this point, you're in the parent process
* and can go about doing whatever else you wanted to do in your program.
*/
std::cout << "QED" << std::endl;
}
To (very) quickly explain what's going on here, the fork() command essentially duplicates the entire C++ program being executed (called a process), but with a different value of pid which is returned from fork(). If pid == 0, then we are currently in the child process; otherwise, we're in the parent process. Since we're in the dispensable child process, we call the execl() command which completely replaces the child process with the shell command you want to execute. The first argument after the path needs to be the filename of the binary, and after that you can pass in as many arguments as you want as null-terminated C strings.
I hope this helps, and please let me know if you need further clarification.
the problem I have understood so far is that you want to pass arguments to c++ executable and it will then pass those arguments further to the system script
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
// argc is the count of the arguments
// args is the array of string (basically the arguments)
int main(int argc, char ** argv) {
// Convetion to check if arguments were provided
// First one or two are the not positional. (these are information related to the binary that is currently being executed)
if (argc < 2) {
printf("Please Provide an Argument");
return 100; // Any number other than 0 (to represent abnormal behaviour)
}
string scriptCommand = "./name-of-script"; // script in your case
// Loop through and add all the arguments.
for (int i = 1; i < argc; i++)
scriptCommand += " " + argv[i];
system(scriptCommand.c_str());
return 0; // Represents a normal exit (execution).
}
Related
Long story short:
I created a program to get the path to a model file, do something with that information and pass on a different set of information, then i tried to create a wrapper for another program that basically catches the command line arguments and funnels some of them to my program to do its thing.
Simplified program flow.
Software --> args[all] --> Wrapper --> args[some] --> Program --> Output
The problem i now have is, calling my program on its own with hard-coded information or command line arguments equal to what the Wrapper would pass on works both flawlessly. The same goes for the Wrapper it works independently.
It also works to have the Wrapper pass on arguments and call the Program if the model information is wrong, which results in a simple string warning. But if the path to the model is correct it gets stuck in an endless loop and i don't know why. Separate runtimes are 8-11s for the Program and maybe 2s for the Wrapper, but i let it run for about 10min and nothing happened after some dummy print code.
Wrapper:
int main(int argc, char* argv[]){
if(argc > 1){
string tmp0 = argv[1];
string tmp1 = "./program " + tmp0;
const char* model = tmp1.c_str();
int status = system(model);
}
else{
cout << "No Model Information.\n";
}
return 0;
}
Parameters would be: Path to a model file and some other stuff, but only the path to the model would be passed on to the program in this case.
Program:
#include "program.hpp"
int main(int argc, char* argv[]){
if(argc > 1){
string tmp = argv[1];
const char* model = tmp.c_str();
cout << program(model);
}
else{
cout << "At least one defined Argument for the Model needs to be given.\n";
}
return 0;
}
Program Function Pseudo Code:
#include <stdio.h>
string program(const char* model){
string tmp
read(model);
if(model has variables) do
tmp = "has variables";
return tmp
}
--- Edit ---
The program function code is in pseudo code because its too complex and specific to list here without a load of libraries and other stuff being listed. If thats necessary i can try to provide it, but as it is i dont have a small or simple example i can give.
--- End edit ---
I don't understand enough about command line arguments to write sophisticated code, so i know this is more or less shitty, but i only need to be able to execute the program from the wrapper somehow and need to be able to read and pass on specific command line arguments. This is just the best i came up with.
Executing the Program code alone, with correct model information: ~10s execution time
Executing the Program code alone, with wrong model information: ~2s execution time
Executing the Wrapper code alone: ~2s execution time
Executing the Wrapper code, calling the Program code with wrong model information: ~2s execution time
Executing the Wrapper code, calling the Program code with correct model information: endless wait
I just dont get why it doesnt progress even though each works separately.
You can use fork() and execvp() in the unistd.h API. Depending on the return of fork() you can have the wrapper wait or end after launching the command.
Save the source file as args.cpp and compile it with the following command:
$ g++ args.cpp -o args && ./args -l -h -a
#include <cstdio>
#include <unistd.h>
#define SPAWNCMD "ls"
int main(int argc, char* argv[])
{
if(argc > 1)
{
printf("Command to spawn: %s ", SPAWNCMD);
for (unsigned i = 1; i < argc; i++)
printf("%s ", argv[i]);
printf("\n");
if (fork())
if (execvp(SPAWNCMD, argv) == -1)
{
printf("Incorrect termination of SPAWNCMD\n");
return 1;
}
}
else
{
printf("No Model Information.\n");
}
printf("Wrapper program end\n");
return 0;
}
The program should execute some loop:
Issue a prompt and read one line of text.
Break that line into words.
If the command is a built-in, take care of it yourself, and return to the read step. Otherwise,
Execute a fork to create a new process. Report the cause of any failure (and, -of course, don't exec if the fork failed).
The child process treats the first word in the list as the name of a command and runs it using an exec call. Send the whole list as the parameters to the program. Report the cause of any failure.
The parent process waits for the child process to exit, then reports its status.
Back to the read for the next command.
I write the head, body, and implementation below
This is the line parsing class:
#include <string>
using namespace std;
/*
* This class takes a C++ string and provides an array of plain C strings
* (array of pointers to char) representing the words in the line.
*/
class LineBreaker {
public:
// Construct the object, providing the line of text to be
// broken up.
LineBreaker(const string &s);
// Clean up.
~LineBreaker() {
delete [] m_data;
delete [] m_parmlist;
}
// Return an pointer to the first slot of an array of pointers
// containing the words in the string sent to the constructor.
// The list is terminated with a NULL pointer.
char **parmlist() { return m_parmlist; }
private:
char *m_data; // Dyn array of characters from the string.
char **m_parmlist; // Array of words
};
This is runner program which is body:
/*
* Simple program to demonstrate the fork/exec/run sequence for creating
* processes in Unix.
*/
#include <iostream>
#include <string>
using namespace std;
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "linebreaker.h"
main()
{
/* Ask for a program to run. This is just the file name of an
executable. */
cout << "Your command? ";
string cmd;
getline(cin, cmd);
LineBreaker breaker(cmd);
/* Create a child process and try to run the program in it. */
if(fork() == 0) {
execv(breaker.parmlist()[0], breaker.parmlist());
cout << "Sorry, the exec failed." << endl;
exit(1);
}
/* See what was the cause of the child processes' demise. */
int status;
wait(&status); /*we only need to change this part, and use something like this if(string(breaker.parlist()[0]) == "exit") */
if(WIFEXITED(status)) cout << "Exited." << endl;
else if(WIFSIGNALED(status)) cout << "Killed." << endl;
else cout << "Mysteriously vanished." << endl;
}
/*
* Note: This program really should check the return values for fork() and for
* exec() to make sure they succeeded, and print an error message if not.
* Failure is indicated by a negative return value. It would also help to use
* errno and strerror() to print a descriptive error message in place of the
* existing exec() failure message, or for the new messages.
*
* It also uses uses gets() and fixed-size buffers, which creates a risk of
* buffer overflow.
*/
This is the implementation :
#include <string>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <list>
#include "linebreaker.h"
LineBreaker::LineBreaker(const string &s)
{
// Copy the string as a character array.
m_data = new char[s.length()+1];
strcpy(m_data, s.c_str());
// Find all the words.
char last = ' ';
list<char *> parts;
for(char *scan = m_data; *scan; ++scan) {
char curr = *scan;
if(isspace(last) && !isspace(curr))
parts.push_back(scan);
else if(!isspace(last) && isspace(curr))
*scan = '\0';
last = curr;
}
// Allocate the array of pointers for exec, and copy the
// pointer into it. Then add the NULL terminator.
m_parmlist = new char * [parts.size()+1];
copy(parts.begin(), parts.end(), m_parmlist);
m_parmlist[parts.size()] = NULL;
}
I want to wrap most of the code of the existing runner program in a while loop, so that it will repeatedly read and execute a command, rather than reading one and exiting.
In the runner program, entering a blank line creates an error (the exec will fail). Change the program so entering a blank line (no words, therefore no command name), doesn't run any command, but the program just returns to the promp then reads another command.
This version searches for command files in the usual places, so don't have to find the full path of the file you want to execute. The runner program uses execv; simply replace with execvp.
Check the return code from each of the fork, exec, or wait calls to check for failure. I want to use errno and strerror to print a message giving the cause of the failure. implement two commands that cannot be run using fork/exec. These are the exit command, and the cd command. These are the build-in commands that the shell must execute itself. For status reporting, if the program exits with a code other than 0 (an error exit), or if it crashes, report that. For normal exit, say nothing. Report the exit code, or the reason for the crash. More on this below.
Not a complete answer, because this is homework, but here’s a hint: while (std::getline( std::cin, cmd ))
This works because getline() returns a reference to the input stream, and when you cast that to a bool value, it will return true while the stream hasn’t yet encountered end-of-file or an error.
I have never used C++ before and my professor said this is supposed to be "very simple", but I can't figure it out. This is what I have so far:
#include <iostream>
#include <cstdio>
#include <cstdlib>
int main(int argc, char *argv[])
{
char command[50];
if (argc==2)
system(command, "./findName.sh", argv[1]);
}
return 0;
My shell script works when I run it by itself but I am not sure how to use a C++ program to run it. For the shell script, the user is supposed to enter a user ID like this:
./findName.sh userID
and the program returns the person's name from a file of names and user IDs like this:
LastName, FirstName
For the C++ program, it needs to pass the information the user enters to the shell script and return the same results.
As I said, I have never used C++ before so I don't know if any of this is right. It is a mix of things I have found online. Thank you for all of your help!!
The easiest way I find to do this is to use std::string as it allows you to concatenate stings easily.
#include <string>
#include <cstdlib>
int main(int argc, char* argv[])
{
std::string command = "./findName.sh";
if(argc == 2)
std::system((command + " " + argv[1]).c_str());
}
But to understand why this works you are going to need to study some books.
First you need to compile the program before you can run it. If your source code file name is progname.cpp you should be able to use this command:
g++ -o progname progname.cpp
And then run the program like this:
./progname userID
1) system("abc.sh " + para1 + " " + para2);
But this method have a limitation, the max length you can pass into is
MAX_ARG_STRLEN is defined as 131072 bytes=32 pages of memory.
2) open a file and read all the value to the file
system("abc.sh < yourfile.txt");
This method is a bit indirect, but you can put unlimited size of value to sh
inside the sh, use a normal read from buf ( or keyboard )
I'm trying to make a program that a bash script runs. I want the bash script to be able to change the state of the c++ program, and the only thing I could find was to use environment variables. Thing is, its seems getenv only gets the value at the time when the program was run.
Bash
export BLINK=1
./blink &
sleep 5s
unset BLINK
C++
int main(int args, char **argv) {
char *blink = getenv("BLINK");
while(blink && blink[0] == '1')
{
std::cout << getenv("BLINK") << std::endl;
usleep(500000);
}
return 1;
}
So what this does is run the blink program, wait 5 seconds then unset the environment. The C++ program however always sees the enviorment value as 1 and never stops. How do I get an updated environment variable while the program is running? Or is there a better way to have a bash script control the state of a c++ program.
EDIT I should note, I do not want to just kill the process either because it has to turn off hardware when it ends.
It is not possible to modify program environment after it is started. You have to use another method of interprocess communication. The simplest one is to register handler for some signal to your app (e.g. SIGUSR1), and then send it using kill -SIGUSR1 <pid> command.
There are also other solutions available, e.g. create named pipe (using pipe shell command), and check periodically if someone wrote something to it. If yes, exit loop.
You can also use sockets if you want, but this could be more complicated.
The C++ programs environment is not changing when you change it in bash - since when you start your program it gets a copy of the parent's environment and has no access to the parent process's environment.
You can use a file to easily share data, however.
Bash
echo "1" > blink.txt
./blink &
sleep 5s
echo "0" > blink.txt
C++
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <unistd.h>
using namespace std;
string getfile(const string& filename) {
ifstream in(filename.c_str(), ios_base::binary);
in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>());
}
int main(int argc, char* argv[]) {
string blink = getfile("blink.txt");
while(blink[0] == '1')
{
std::cout << getfile("blink.txt") << std::endl;
usleep(500000);
}
return 1;
}
I'm relatively new to c++, and I'm just making some simple programs.
One of my programs will need to open up a different .exe file. This .exe file will ask for 2 or 3 file names, then run and exit.
Just to test this out, I created a simple_calc.exe file, that ask for value1, then value2 then multiply them.
So let's say I want to create a "call_other_file.exe" and automatically run "simple_calc.exe" with value1 and value2 taken from "call_other_file.exe"s file.
How can I proceed to do that?
After searching a bit, i see something like:
system("simple_calc.exe -val1 -val2").
But that doesn't work for me. Or I'm not sure how to define val1 and val2...
edit: the program I want to access (simple_calc.exe in the example), I can not change the code there, I don't have access to it's .cpp file.
Any suggestions?
i see something like: system("simple_calc.exe -val1 -val2")
It should work. The reason why that didn't work might be that you didn't put int argc, char* argv[] in your "simple_calc"'s main function.
//simple_calc.cpp
int main(int argc, char* argv[])
{
if (argc == 2)
{
cout << "Error: At least two argument must be exist.";
return -1;
}
return 0;
// After that, you can use 'argv' arguments to calculate what you want to calculate. Also, in order to calculate them, you also need to convert 'argv' to integer or double, since they are string or char array.
}
For more information on C++ comand-line arguments see this site below:
http://www.tutorialspoint.com/cprogramming/c_command_line_arguments.htm
When you add the command-line arguments to your simple_calc.cpp, you can use this simple_calc.exe val1 val2. To call another program from your C++ program, you need system calls. In your main function;
system('simple_calc.exe')
You also need to know about how windows console work, if you are using windows. If you are using linux, its console commands are also different.
My suggestion is that you must first learn how consoles work different operating systems.
There are various ways to have two separate programs communicate with one another, but the system() function is probably the simplest; it just runs a string of text as though it were entered in a console window.
Basic example
The main program simply runs the other program with two arguments: hello and world.
/* main.c */
#include <stdlib.h>
int main() { return system("./other hello world"); }
The two arguments will be passed to the other program as C-style strings via the argv[] array. Note that they will be stored as the second and third elements, since the first item (argv[0]) will be the path to the program itself.
/* other.c */
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
for (i = 1; i < argc; ++i) { printf("%s\n", argv[i]); }
return 0;
}
The output of the above programs will look like this:
hello
world
Process returned 0 (0x0) execution time : 0.004 s
Press ENTER to continue.
Arguments with spaces
As you may have noticed, arguments are space-separated. If you need to pass a string with spaces as a single parameter, you'll need to enclose it in quotes:
/* main.c */
#include <stdlib.h>
int main() { return system("./other \"this is all one string\" \"and so is this\" bye"); }
This would produce the following result:
this is all one string
and so is this
bye
Process returned 0 (0x0) execution time : 0.004 s
Press ENTER to continue.
Non-string arguments
Since the arguments are given as strings, you'll need to convert them into numbers (using conversion functions such as strtod(), atoi(), or atof()) if necessary. Here's an updated version of main.c:
/* main.c */
#include <stdlib.h>
int main() { return system("./other 4 6"); }
...and here's the corresponding other.c file:
/* other.c */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int total, i;
for (total = 0, i = 1; i < argc; ++i) { total += atoi(argv[i]); }
printf("TOTAL: %d\n", total);
return 0;
}
This produces the following output:
TOTAL: 10
Process returned 0 (0x0) execution time : 0.005 s
Press ENTER to continue.