1

Is it possible to send an openssl command in a bash script, and then have the script wait for a prompt before outputting the correct text to stdin?

I want to be able to:

  • Send an openssl command
  • Wait for line X to appear
  • Report a fault if line X does not appear
  • Wait for line Y to appear
  • Output to stdin
  • More processing...

My current approach puts the openssl command in the background, pipes the output to a file (using tee, so I also see it in the terminal) and uses a while loop to continuously read the output.

My problem lies when I output to stdin. My script detects that line Y has appeared, but using cat <<< "my_input" does not work. I know that the openssl command is waiting for the input, because if I manually enter the command at that point, all is OK.

Any ideas what I'm missing? Or is there a better approach?

Note: I'm hoping for an approach which does not use a third party application, such as 'expect' mentioned below.

2
  • 1
    Expect was created to solve this type of problem. In addition to the original TCL library, there are versions for Python, Perl, Ruby, and many others. Commented May 8, 2017 at 15:27
  • I'm hoping to not have to use any external libraries. I've updated my question to include this information. Commented May 8, 2017 at 16:34

1 Answer 1

4

If you are sticking to Bash: you need to call openssl in such a way that you have a file handle to its stdin in order to script sending data to it. For example, if you have Bash 4,

# Run openssl with stdin and stdout attached to pipes stored in ${OPENSSL[*]}
coproc OPENSSL {
    openssl ...
}

# Wait for a line to appear
while read -r -u ${OPENSSL[0]} line; do
    if [[ ${line} = X ]]; then
        break
    fi
done

# Send something to the input
echo 'hello, world!' >&${OPENSSL[1]}

# Close input
exec {OPENSSL[1]}>&-

# Forward everything from the output to our stdout
cat <&${OPENSSL[0]}

If you have an earlier version of Bash you will need to use named pipes order to attach to a process's stdin and stdout both.

If you only need to attach to stdin there are a few tricks: either redirect a subshell (which may be tricky to coordinate with reading data outside the subshell)

{
    echo 'hello, world! (from a subshell)'
} | openssl ... | tee ...

or use process substitution.

exec {OPENSSL}> >(openssl ... | tee ...)
echo 'hello, world!' >&${OPENSSL}
exec {OPENSSL}>&-
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, that makes sense! Using your first approach, I get the following error: {OPENSSL[0]}: ambiguous redirect. This points to the cat <&{OPENSSL[0]} line. Any ideas?
@mfisher91 Oops, that should be cat <&${OPENSSL[0]}, and a similar fix in a couple other places.
That's great. One more question; so, I want to put this in a loop, so my program will make the openssl connection & perform the task every X minutes. How do I kill the current co-process? I don't want to leave lots of co-processes open!
@mfisher91 The PID will be in $OPENSSL_PID because we named the array ${OPENSSL[*]}, so you could kill it. But openssl should terminate naturally on its own after you close its stdin and fully read its stdout.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.