Writing a Shell Script that runs my program with inputs - c++

Ok so I created my own shell, and I've tested it plenty on my own, but I need shell scripts that will run it and test it.
I've create a script which consist of this:
#!/bin/bash
echo "ls && echo dog" | ./a.out
However, all it does is print the command prompt "$" infinitely, and I have to force quit the program. therefore I am pretty sure my program does not like my script lol. My program works by using getline to capture the user input until they push <enter> and the boost library to tokenize the string and look for connector e.g "||" "&&" ";" and and so on, then run the commands. All of this is done in a while loop that loops until the user types exit and I close my program. Being as I am new to writing scripts I am sure I probably am not writing my script in the best of manners. I created a simple program to ask for your age and then output it and this script method works for that, but being as my shell isn't as simple I am not surprised this scrip doesn't seem to work.
string user_input;
bool good = true;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
while(good){
//command prompt
cout << "$ ";
//read in user input
getline(cin, user_input);
//tokenize user input
tokenizer tok(user_input);
//parse and execute commands inputed by user in string
//only exit while loop if user command is <exit> good = false
}
my shell works if I execute the program normally and I enter inputs into the program what I need is a shell script that I can use to run and test the program for me. Ex. if I type ./script.sh in the standard linux shell it will run my script which will then execute my a.out and then test my own shell with a variety of commands Examples being ls echo ...

You should exit the shell when you reach EOF (End Of File). Getline while return -1 in that case.
I can't think of any other advice as you didn't provide any code, but this might resolve the infinite loop issue.

Related

How detect a input injected from bash in a background process using std::in and getline()

I have a binary compiled in Cpp with the following code:
std::string input;
getline(std::cin, input);
std::cout << "Message given: " << input << std::endl;
If I execute this example, and write in the terminal "Hello world!" works perfectly:
Message given: Hello world!
Now, I launch the executable in redirecting stdout:
./basicsample >> output/test
If I try to inject inputs using file descriptor:
echo "Hello world!" > /proc/${PID}/fd/0
The message appear in terminal that launched the process:
[vgonisanz#foovar bash]$ ./basicsample >> output/test
Hello world!
But the message no appear in the programs output. I expect to get the message processed by getline, and it is not detected! But, If I write directly in that bash, the program get the input. I'm trying to do a script to inject inputs in a background process but it is not working.
How could I inject inputs to be detected into the process without do it manually?
UPDATE:
It seems that using expect, this could work, but I will prefer to avoid dependencies like this. After several tries, the best way to do it without dependencies is to use a pipe, in example:
mkdir tmp; mkfifo tmp/input.pipe; nohup ./basicsample tmp/user.out 2> tmp/nohup.err
This will run the creating a input pipe, an output for console and error.
Then, just feed the pipe using:
echo "Hello world!" > tmp/input.pipe
The problem of this is, the pipe works only once. After getting an input, it won't never listen it again. Maybe this is the way but I don't know how to avoid to lost the focus.
I tried to redirect it using several ways like files, etc, but it doesn't works. Thanks in advance.
The best way to do it without dependencies is to use a pipe, in example:
mkdir tmp
mkfifo tmp/input.pipe
(tail -f tmp/input.pipe) | ./basicsample > tmp/log.0 &
This will run creating an input pipe and an output saved in log file. You can prevent console blocking using the operator & to launch it in background.
Then inject data using:
echo "YOUR_STRING" > tmp/input.pipe
It should work for your posed problem.

GDB stuck in infinite loop when debugging progam with standard input

I'm using GDB to do some reverse engineering of a basic C program. The program does not accept command line input. It does accept input from standard in during run time. I'm trying to script the standard in by doing
run < temp
Where temp is a file containing something like
1
0
AAAAAAAAA
AAAAA
0
Unfortunately, when I do this, GDB appears to loop infinitely over this programs input.
I tried to make this file using python
python -c 'print "AAAAA"' > temp
And with the solution presented here: How to debug a program that takes user input from stdin with GDB?
But no luck. When I just step through the program with GDB, I can pass input via standard in and that work's just fine.
I'm a bit stumped...

Open a Shell Program, pass it params, and return the results

I'm writing a shell script in c++, and I'm trying to write a way to make some basic unit tests by comparing the output generated by the runtime of system and my shell diff-wise.
Based on reading through alot of StackOverflow articles, this is what I am using to capture the output of a simple ls command:
FILE *syst;
char buff[512];
string systout ( "" );
if(!(syst = popen("ls ", "r"))){
cout << "Failed! " << endl;
return 1;
}
while(fgets(buff, sizeof(buff), syst)!=NULL){
systout.append(buff);
}
fflush(syst);
pclose(syst);
This works just fine.
The issue is I cannot find a way of getting this to work for my shell script.
Normally I run it using sudo ./shell, then ls.
This is what I have right now, but it doesn't work. I think its not finding my shell or something, but there's nothing outputted. I know the shell works, because I've manually run it, and the results match the expected results.
FILE *shel;
char buff2[512];
string shelout ( "" );
if(!(shel = popen("sudo ./shell ls ", "r"))){
cout << "Failed! " << endl;
return 1;
}
while(fgets(buff2, sizeof(buff2), shel)!=NULL){
shelout.append(buff2);
}
fflush(shel);
pclose(shel);
Any ideas?
When you say "Normally I run it using sudo ./shell, then ls", what you are saying is:
You execute "sudo", passing it one argument "./shell".
sudo runs "./shell" (as root, but that's not relevant here).
The "shell" executable prompts for a command of some kind, you type "ls" and you get the output.
You are attempting to automate it via the following piece of code:
popen("sudo ./shell ls ", "r")
What this does is
Executes "sudo", and passes the "sudo" command two arguments: "./shell" and "ls".
Which is completely different than happens in the first part, steps 1 through 3; and which is why it doesn't work.
The simplest thing for you to do is to modify your "./shell" to support alternative invocation means of passing it commands as arguments, instead of having "./shell" prompt interactively for commands to execute.
You can use the script command for capturing your input and output.
Afterwards you can compare the output for both cases (using diff or cmp and filtering the differences with a simple program).

Custom interactive shell

I've run into the following problem: My console utility should be running as a process (hope it's the right term) so every command goes to it directly. Like gnuplot, interactive shells (irb, etc.).
This shows what I'm talking about:
Mikulas-Dites-Mac-2:Web rullaf$ command
Mikulas-Dites-Mac-2:Web rullaf$ irb
>> command
NameError: undefined local variable or method `command' for main:Object
from (irb):1
>> exit
Mikulas-Dites-Mac-2:Web rullaf$
first command is executed as shell command, but after I enter irb, it's not. You get the point.
irb puts console into some special mode, or it simply parses the given input itself in some loop?
Is here any proper way to create such a behavior in c++? Thanks
You have to parse the input yourself. Depending on the complexity of the input, this might be accomplished by some simple string matching for trivial cases. A very simple example:
#include <iostream>
#include <string>
int main()
{
std::string input;
for(;;)
{
std::cout << ">>";
std::cin >> input;
if(input=="exit")
return 0;
else if(input=="test")
std::cout << "Test!\n";
else
std::cout << "Unknown command.\n";
}
}
Obviously, this little program will print a prompt (>>) and understand the commands exit and test and will print Unknown command. on all other commands.
For everything else, you probably want to learn some more about pattern matching or parsing; Google is your friend (take a look at bison for example and a good tutorial).
To parse your command line, you can use Boost.Program_options.

Checking return value of a C++ executable through shell script

I am running a shell script on windows with cygwin in which I execute a program multiple times with different arguments each time. Sometimes, the program generates segmentation fault for some input arguments. I want to generate a text file in which the shell script can write for which of the inputs, the program failed. Basically I want to check return value of the program each time it runs. Here I am assuming that when program fails, it returns a different value from that when it succeeds. I am not sure about this. The executable is a C++ program.
Is it possible to do this? Please guide. If possible, please provide a code snippet for shell script.
Also, please tell what all values are returned.
My script is .sh file.
The return value of the last program that finished is available in the environment variable $?.
You can test the return value using shell's if command:
if program; then
echo Success
else
echo Fail
fi
or by using "and" or "or" lists to do extra commands only if yours succeeds or failed:
program && echo Success
program || echo Fail
Note that the test succeeds if the program returns 0 for success, which is slightly counterintuitive if you're used to C/C++ conditions succeeding for non-zero values.
if it is bat file you can use %ERRORLEVEL%
Assuming no significant spaces in your command line arguments:
cat <<'EOF' |
-V
-h
-:
-a whatnot peezat
!
while read args
do
if program $args
then : OK
else echo "!! FAIL !! ($?) $args" >> logfile
fi
done
This takes a but more effort (to be polite about it) if you must retain spaces. Well, a bit more effort; you probably use an eval in front of the 'program'.