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.

Christian Fritz
  • 20,641
  • 3
  • 42
  • 71
stilliard
  • 762
  • 8
  • 27
  • does openvpn actually terminate, or does it need to keep running? If it terminates then `sudo openvpn --config FILE && ssh SERVER` would work. – Christian Fritz Jan 08 '14 at 16:38
  • Hi @ChristianF, no openvpn does not terminate, it only terminates when i close the vpn connection. – stilliard Jan 08 '14 at 16:39

2 Answers2

27

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.

Community
  • 1
  • 1
Michael Kropat
  • 14,557
  • 12
  • 70
  • 91
  • 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. – stilliard Jan 08 '14 at 17:28
  • @MarcelM. I've updated the answer with my best attempt – Michael Kropat Oct 27 '14 at 22:11
  • 3
    Related to this: how would I stop the original background process (e.g. openvpn)? – Johannes Rudolph Nov 28 '16 at 15:32
  • 1
    When you want to exit status 1 when you encounter a different string `sed -e '/Completed/q' -e '/Failed/q1'`. – avalanchy Sep 21 '18 at 10:23
  • 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? – ingli Apr 07 '20 at 17:43
  • This is great, thanks! I had trouble running this in a single line. I was missing the ";" right before "sed" – khuezy Feb 05 '23 at 20:59
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
Christian Fritz
  • 20,641
  • 3
  • 42
  • 71
  • 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. – stilliard Jan 08 '14 at 17:22