How do I get ssh to run in the background without using -f?

Solution 1:

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

Solution 2:

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.