bash sequence: wait for output, then start next program
Asked Answered
K

2

9

In my case I have to run openvpn before ssh'ing into a server, and the openvpn command echos out "Initialization Sequence Completed".

So, I want my script to setup the openvpn and then ssh in.

My question is: How do you execute a command in bash in the background and await it to echo "completed" before running another program?

My current way of doing this is having 2 terminal panes open, one running:

sudo openvpn --config FILE

and in the other I run:

ssh SERVER

once the the first terminal pane has shown me the "Initialization Sequence Completed" text.

Knot answered 8/1, 2014 at 16:29 Comment(2)
does openvpn actually terminate, or does it need to keep running? If it terminates then sudo openvpn --config FILE && ssh SERVER would work.Primine
Hi @ChristianF, no openvpn does not terminate, it only terminates when i close the vpn connection.Knot
D
26

It seems like you want to run openvpn as a process in the background while processing its stdout in the foreground.

exec 3< <(sudo openvpn --config FILE)
sed '/Initialization Sequence Completed$/q' <&3 ; cat <&3 &
# VPN initialization is now complete and running in the background
ssh SERVER

Explanation

Let's break it into pieces:

  1. echo <(sudo openvpn --config FILE) will print out something like /dev/fd63
    • the <(..) runs openvpn in the background, and...
    • attaches its stdout to a file descriptor, which is printed out by echo
  2. exec 3< /dev/fd63
    • (where /dev/fd63 is the file descriptor printed from step 1)
    • this tells the shell to open the file descriptor (/dev/fd63) for reading, and...
    • make it available at the file descriptor 3
  3. sed '/Initialization Sequence Completed$/q' <&3
    • now we run sed in the foreground, but make it read from the file descriptor 3 we just opened
    • as soon as sed sees that the current line ends with "Initialization Sequence Completed", it quits (the /q part)
  4. cat <&3 &
    • openvpn will keep writing to file descriptor 3 and eventually block if nothing reads from it
    • to prevent that, we run cat in the background to read the rest of the output

The basic idea is to run openvpn in the background, but capture its output somewhere so that we can run a command in the foreground that will block until it reads the magic words, "Initialization Sequence Completed". The above code tries to do it without creating messy temporary files, but a simpler way might be just to use a temporary file.

Dollfuss answered 8/1, 2014 at 17:11 Comment(6)
Thanks, that works perfectly! I haven't tried out bash's process substitution before so i'll be sure to read up on this now.Knot
@MarcelM. I've updated the answer with my best attemptDollfuss
Related to this: how would I stop the original background process (e.g. openvpn)?Cecilycecity
When you want to exit status 1 when you encounter a different string sed -e '/Completed/q' -e '/Failed/q1'.Claudieclaudina
I want to use the code in a shell script #!/bin/bash exec 3< <(sudo openvpn --config /etc/openvpn/server.ovpn) sed '/Initialization Sequence Completed$/q' <&3 ; cat <&3 & ssh server. executing that script throws me an error line 2: syntax error near unexpected token <''. Have I misunderstood something obvious here?Bant
This is great, thanks! I had trouble running this in a single line. I was missing the ";" right before "sed"Mckenna
P
2

Use -m 1 together with --line-buffered in grep to terminate a grep after first match in a continuous stream. This should work:

sudo openvpn --config FILE | grep -m "Initialization Sequence Completed" --line-buffered && ssh SERVER
Primine answered 8/1, 2014 at 17:0 Comment(1)
I just tried your command but it didn't work, it just paused which is what happens to the ssh command if it runs before the openvpn command is complete, so i think its being called before its complete. It does show the "Initialization Sequence Completed" line, but doesn't do anything after that.Knot

© 2022 - 2024 — McMap. All rights reserved.