5

I'm attempting to create an ssh tunnel, spin it off into a background process, and write a pid file which I can later use to kill it. I CAN run ssh with -f, but then I don't have a handle on its PID.

However, when I attempt to run the script below via nohup or setsid, control is never returned to the shell from which I attempt to daemonize the script.

#!/bin/sh                                                 

while getopts ":v" flag; do
    case $flag in
        v|verbose) verbose=1;;
        :) echo "option -$lastflag requires an argument"; exit 1;;
    esac 
    lastflag="$flag"
    shift $((OPTIND - 1)); OPTIND=1
done

ssh  -p '2222'  -nNL '5984:localhost:5984' 'blah@foo.com' &
pid=$!
sleep 2;
ps -p $pid >/dev/null 2>&1 || exit 1
echo $pid > "var/couchdb-tunnel.pid"
wait

Invocation:

nohup script.sh
setsid script.sh

How I do convince ssh (I assume) to let go of the terminal? Is there some other way I can accomplish what I want?

vezult
  • 400
  • 2
  • 5
  • 14

3 Answers3

3

The shell builtin you're looking for is disown, which re-parents backgrounded jobs to init so that the script can exit leaving them safely in the background. You probably want to redirect output to /dev/null (or a log file) in order to avoid getting output in the shell after starting the script.

ssh hostname 'command' &>/dev/null &
disown
Kyle Smith
  • 9,563
  • 1
  • 30
  • 32
  • disown is bash specific, and doesn't really offer any different results than nohup or setsid (which are not bash-specific). However, it turns out that redirecting all output from ssh to /dev/null allows all of these methods (nohup, setsid, disown) to work as expected. – vezult Feb 28 '12 at 22:33
  • Ah, I did try it with /bin/sh, but on a RHEL box where /bin/sh is a symlink to /bin/bash :) – Kyle Smith Feb 28 '12 at 22:35
  • Had same problem, (ssh won't let go), found redirecting stdout of setsid > /dev/null did it. Interestingly, stderr didn't need same treatment. – FDS Mar 20 '15 at 05:16
1

Isn't the wait causing your script to erm wait ? From the man page ...

wait [n ...] Wait for each specified process and return its termination status. Each n may be a process ID or a job specifi- cation; if a job spec is given, all processes in that job’s pipeline are waited for. If n is not given, all currently active child processes are waited for, and the return status is zero. If n specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process or job waited for.

So your script is waiting for the ssh tunnel to complete before returning to the prompt. just remove the wait and you'll get a prompt back and your tunnel will be running in the background.

user9517
  • 114,104
  • 20
  • 206
  • 289
  • erm..no. I want to daemonize the script. I don't care if the script itself keeps running, but I don't want for the shell in which it was invoked to have to wait for it to finish. – vezult Feb 29 '12 at 14:14
  • Ok, your script is doing nothing after it has written to the pid file and the tunnel is independent of it so as shown there really isn't much reason to keep it running. If you want to keep it running while it waits for the tunnel to exit then just put an `&` after the script name. This seems to work in my tests. – user9517 Feb 29 '12 at 14:55
  • So, there are three levels: main script --> wrapper --> tunnel. The ssh tunnel isn't independant of the wrapping script. If I actually daemonize the tunnel I can't capture its PID. So, I just run it in the background of the wrapper script, and daemonize the wrapper script instead. Because the tunnel is a child of the wrapper, killing the wrapper terminates the tunnel. – vezult Feb 29 '12 at 15:42
  • You're getting different results to me. I can run your script without the wait and it terminates with the tunnels `pid` in the `/var/couchdb-tunnel.pid` and the tunnel remains open. I can run your script unchanged with an `&` at the end and it runs, puts the pid in the file and waits for the tunnel to end but returns the prompt to the shell. – user9517 Feb 29 '12 at 16:03
0

I use screen to have different connections and scripts running in the same terminal window. This also allows me to shutdown my machine, go home, turn my machine back on and reload the screen session I wanted to keep tabs on what's going on.

Of course this is assuming I'm SSH'd into another machine from my terminal.