How can I connect to a terminal and program at the same time in bash

So, I'm trying to make a script to automate testing (input and output) of my C program, and I'm trying to make the input stay on the screen so that I know what is going on.

So far I have only tried the pipeline:

foo < input.txt 

and

 cat input.txt | tee dev/tty |foo 

which is not working for me yet.

So, assuming the input file would look like this:

 123 321 

Ideally, an IO would look like this:

 Input: 123 Echo: 123 Input: 321 Echo: 321 

but he turns into

 123 321 Input: Echo: 123 Input: Echo: 321 

Are there other methods that can be used to test my C program? Where else can I approach this result? Is it possible for me to write another C program that can achieve something like this?

+5
source share
4 answers

The output of stdout tee (to stdin from foo ) and duplicate entries (to your dev) are not time synchronized. Your tty consumes input faster than foo , and libc buffering makes it even worse. If interactive automation is what you're looking for, take a look at expect .

+1
source

how about just

 cat input.txt ; cat input.txt | foo ; 

the first part prints the input, the second part prints the result.

Your alternative is to expose the print statements in your code so that the sub-page of the input being processed is printed before the corresponding output at each iteration.

0
source

The following script feeds the program when it detects that it is locked in syscall read() on standard input, and prints the same text on standard output. As a result, the output of the program and the contents of the standard input are correctly interspersed.

Application:

$ simulate_user_input program args ...

Example:

 $ cat > test_script <<'END' #!/usr/bin/env bash echo -n "First name: " read -r first_name echo -n "Second name: " read -r second_name echo "Hello $first_name $second_name" END $ chmod +x test_script $ ./simulate_user_input ./test_script <<< $'John\nSmith' First name: John Second name: Smith Hello John Smith 

simulate_user_input

 #!/usr/bin/env bash if [ $# -eq 0 ] then cat<<END Usage: $(basename "$0") command args ... END exit 1 fi #set -x if [ "$1" == "-simulate" ] then app_stdin="$2/app_stdin" user_stdin="$2/user_stdin" user_stdout="$2/user_stdout" exec > "$app_stdin" 3< "$user_stdin" 4> "$user_stdout" while read -r -n 6 -t 0.1 line do if [[ $line == 'read(0' ]] then read -u 3 -r line || { cat > /dev/null; exit 0; } echo "$line" >&4 echo "$line" fi done exit 0 fi cleanup() { rm -rf "$tmpdir" if [ "$(jobs -r|wc -l)" -ne 0 ] then kill %1 %2 fi } tmpdir="$(mktemp -d)" trap "cleanup" EXIT app_stdin="$tmpdir/app_stdin" user_stdin="$tmpdir/user_stdin" user_stdout="$tmpdir/user_stdout" mkfifo "$app_stdin" mkfifo "$user_stdin" mkfifo "$user_stdout" cat "$app_stdin"|strace -e read -o "|$0 -simulate '$tmpdir'" " $@ " & cat < "$user_stdout" & cat > "$user_stdin" wait 
0
source

Here's a small Python 2 program that will do this, provided that your target program ( foo ) will produce one line for each line of input:

 #!/usr/bin/env python import sys, subprocess sp = subprocess.Popen(sys.argv[1:], stdin=subprocess.PIPE, stdout=subprocess.PIPE) for input_line in sys.stdin: print('Input: ' + input_line.rstrip('\r\n')) sp.stdin.write(input_line) sp.stdin.flush() output_line = sp.stdout.readline() print('Output: ' + output_line.rstrip('\r\n')) 

If you save this as tee.py , you can test it with

 echo -e '123\n321' | tee.py cat - 

for a general reproducible test, or

 echo -e '123\n321' | tee.py foo 

for your specific example.


PS: if you want it in Python 3, you need to change two lines:

  sp.stdin.write(input_line.encode('utf-8')) 

and

  output_line = sp.stdout.readline().decode('utf-8') 
0
source

Source: https://habr.com/ru/post/1258112/


All Articles