Periodic STDIN for a bash command through Python 3 - python-3.x

I have a simple C++ program:
#include<bits/stdc++.h>
using namespace std;
int main() {
while(1) {
string s;
cout << "Enter command: ";
cin >> s;
if (s == "end") {
break;
}
cout << "Sent command: " << s << "\n";
}
return 0;
}
I want to read a set of commands from another file, say cmd.txt as below:
start
go 10
r 20
go 10
stop
end
and so on. But it should be periodic, i.e.,
read start; wait for 1 minute
read go 10; wait for 1 minute... and so on.
To solve this, I thought I can use subprocess from Python 3 and then issue the bash command with stdin being read from the file and supplied periodically. But, the command seems to be blocking in the first place itself.
Here is the script that I have tried so far:
import subprocess
patterns = ['rectangle.txt', 'hexagon.txt']
subprocess.run(["g++", "reads.cpp", "-o", "reads"], shell=True)
for ptr in patterns:
print('Testing commands from ', ptr)
subprocess.run(["./reads"], shell=True)
commands = open(ptr, 'r').readlines()
for cmd in commands:
print(cmd, end='')
So, how can I achieve this? Or should I use only Bash for this?

Related

pipe command make standard input broken

I have two processes: t1.cpp and t2.cpp.
t1.cpp and t2.cpp are simplified ,I want to describe the problem easily.
//t1.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "hello\n"
<< "world\n"
<< "ok ok\n";
return 0;
}
//t2.cpp
#include <iostream>
#include <limits>
using namespace std;
int main()
{
string str;
while(getline(cin,str)){
cout << str <<endl;
}
//cin.clear();
//flush the cin
//cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
char x;
cin >> x;
return 0;
}
After compiling t1.cpp and t2.cpp. I execute them in this way ./t1 | ./t2.
Problems occur! cin >> x; in t2.cpp failed! I have no chance to type from the keyboard.
It seems the pipe command implements by redirecting the STDIN_FILENO. Does it forbid the standard input simultaneously?
My harsh requirements is obtain data from the output of t1 with shell command |,in addition,I want interact with users in t2.For example,I would display Sure to del?[y/n],and wait users's anwser.
Actually, there is something you can do in the C++ code. t1 has to read from stdin and echo that to stdout, which is redirected. You can do something like this at various places:
T value;
std::cin >> value;
std::cout << value;
Or to emulate the behaviour of the shell command in the comments (append stdin after t1 has finished writing its data to stdout):
std::copy(std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(std::cout));
Finally,we deal this problem using "/dev/tty"
FILE *file = fopen("/dev/tty","r");
if(NULL == file){
/*error*/
}
int ch = fgetc(file);
if('y' == ch || 'Y' == ch){
/*balabala*/
}
when stdin or stdout was redirected , we also can read or write from the /dev/tty.

C++ : Run Code Error with EOF ( End-Of-File )

I'm using Visual Studio Community 2017 to run the following code but i get an error. Can anyone tell me what is the problem ?
C++ Code :
#include <iostream>
using namespace std;
int main()
{
int a, b;
while ((cin >> a >> b) != EOF)
{
cout << "Sum is: " << a + b << endl;
}
return 0;
}
Most likely issue is the EOF - the >> operator returns a reference to a stream object - not return an integer like EOF
just using tis may work ok - it will continue until a fail bit is set.
while (cin >> a >> b)

Get the content on the command line with an external promgram

I would like to write a small program which will analyize my current input on the command line and generate some suggesstions like those search engines do.
The problems is how can an external program get the content on command line? For example
# an external program started and got passed in the PID of the shell below.
# the user typed something in the shell like this...
<PROMPT> $ echo "grab this command"
# the external program now get 'echo "grab this command"'
# and ideally the this could be done in realtime.
More over, can I just modify the content of current command line?
EDIT
bash uses libreadline to manage the command line, but still I can not imagine how to make use of this.
You could write your own shell wrapper using c. Open bash in a process using popen and use fgetc and fputc to write the data to the process and the output file.
A quick dirty hack could look like this (bash isn't started in interactive mode, but otherwise should work fine. --> no prompt):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
pid_t pid;
void kill_ch(int sig) {
kill(pid, SIGKILL);
}
/**
*
*/
int main(int argc, char** argv) {
int b;
FILE *cmd = NULL;
FILE *log = NULL;
signal(SIGALRM, (void (*)(int))kill_ch);
cmd = popen("/bin/bash -s", "r+");
if (cmd == NULL) {
fprintf(stderr, "Error: Failed to open process");
return EXIT_FAILURE;
}
setvbuf(cmd, NULL, _IOLBF, 0);
log = fopen("out.txt", "a");
if (log == NULL) {
fprintf(stderr, "Error: Failed to open logfile");
return EXIT_FAILURE;
}
setvbuf(log, NULL, _IONBF, 0);
pid = fork();
if (pid != 0)
goto EXEC_WRITE;
else
goto EXEC_READ;
EXEC_READ:
while (1) {
b = fgetc(stdin);
if (b != EOF) {
fputc((char) b, cmd);
fputc((char) b, log);
}
}
EXEC_WRITE:
while (1) {
b = fgetc(cmd);
if (b == EOF) {
return EXIT_SUCCESS;
}
fputc(b, stdout);
fputc(b, log);
}
return EXIT_SUCCESS;
}
I might not fully understand your question but I think you'd basically have two options.
The first option would be to explicitly call your "magic" program by prefixing your call with it like so
<PROMPT> $ magic echo "grab this command"
(magic analyzes $* and says...)
Your input would print "grab this command" to stdout
<PROMPT> $
In this case the arguments to "magic" would be handled as positional parameters ($*, $1 ...)
The second option would be to wrap an interpreter-like something around your typing. E.g. the Python interpreter does so if called without arguments. You start the interpreter, which will basically read anything you type (stdin) in an endless loop, interpret it, and produce some output (typically on stdout).
<PROMPT> $ magic
<MAGIC_PROMPT> $ echo "grab this command"
(your magic interpreter processes the input and says...)
Your input would print "grab this command" to stdout
<MAGIC_PROMPT> $

Two way communication with process

I have given some compiled program. I want to communicate with it from my bash script by program stdin and stdout. I need two way communication. Program cannot be killed between exchange of information. How I can do that?
Simple example:
Let that program be compiled partial summation (C++) and script results will be squares of that sums. Program:
int main() {
int num, sum = 0;
while(true) {
std::cin >> num;
sum += num;
std::cout << sum << std::endl;
}
}
My script should looks like that:
for i in 1 2 3 4; do
echo "$i" > program
read program to line;
echo $((line * line))
done
If in program I have for(int i = 1; i <= 4; ++i), then I can do something like that:
exec 4< <(./program); # Just read from program
for i in 1 2 3 4; do
read <&4 line;
echo "sh: $((line * line))";
done
For more look here. From the other hand, if in program I have std::cout << sum * sum;, then solution could be:
exec &3> >(./program); # Write to program
for i in 1 2 3 4; do
echo "$i" > &3
done
My problem is two way communication with other process / program. I don't have to use exec. I cannot install third party software. Bash-only solution, without files, will be nice.
If I run other process, it will be nice to know pid to kill that at the end of script.
I think about communication with two or maybe three processes in the future. Output of firs program may dependents on output of second program and also in second side. Like communicator of processes.
However, I cannot recompile programs and change something. I have only stdin and stdout communication in programs.
If you have bash which is newer than 4.0, you can use coproc.
However, don't forget that the input/output of the command you want to communicate might be buffered.
In that case you should wrap the command with something like stdbuf -i0 -o0
Reference: How to make output of any shell command unbuffered?
Here's an example
#!/bin/bash
coproc mycoproc {
./a.out # your C++ code
}
# input to "std::cin >> num;"
echo "1" >&${mycoproc[1]}
# get output from "std::cout << sum << std::endl;"
# "-t 3" means that it waits for 3 seconds
read -t 3 -u ${mycoproc[0]} var
# print it
echo $var
echo "2" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var
echo "3" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var
# you can get PID
kill $mycoproc_PID
output will be
1
3
6
If your bash is older than 4.0, using mkfifo can do the same thing like:
#!/bin/bash
mkfifo f1 f2
exec 4<> f1
exec 5<> f2
./a.out < f1 > f2 &
echo "1" >&4
read -t 3 -u 5 var
echo $var
rm f1 f2
Considering that your C++ program reads from standard output, and prints to standard output, it's easy to put it inside a simple chain of pipes:
command_that_writes_output | your_cpp_program | command_that_handle_output
In your specific case you probably need to modify the program to only handle one single input and writing one single output, and remove the loop. Because then you can do it very simple, like this:
for i in 1 2 3 4; do
result=`echo $i | ./program`
echo $((result * result))
done

How to prefill command line input

I'm running a bash script and I'd like to prefill a command line with some command after executing the script. The only condition is that the script mustn't be running at that time.
What I need is to ...
run the script
have prefilled text in my command line AFTER the script has been stopped
Is it even possible? All what I tried is to simulate a bash script using
read -e -i "$comm" -p "[$USER#$HOSTNAME $PWD]$ " input
command $input
But I'm looking for something more straightforward.
You need to use the TIOCSTI ioctl. Here's an example C program that shows how it works:
#include <sys/ioctl.h>
main()
{
char buf[] = "date";
int i;
for (i = 0; i < sizeof buf - 1; i++)
ioctl(0, TIOCSTI, &buf[i]);
return 0;
}
Compile this and run it and "date" will be buffered as input on stdin, which your shell will read after the program exits. You can roll this up into a command that lets you stuff anything into the input stream and use that command in your bash script.

Resources