1

I am running the following SSH command:

ssh "root@$ip" 'nohup sh -s' < ./do_sync &

My goal is to execute the contents of do_sync (a shell script) on the remote host. I'm doing it this way because, for reasons I won't go into, I can't transfer the actual script file to that machine and execute it there.

Not sure if it's relevant, but the remote machine is actually an Android x86 device. However, I'm not doing anything Android-related on it. The Java VM isn't even running. It's just Android's version of Linux, with some busybox utilities on it. It has no bash and the sh it uses seems very basic/old. I'm not sure if it's fully POSIX compliant. It hasn't been until now that I've run into issues getting the behavior I want, so just in case it's OS-related I wanted to mention this detail.

This command works, but the ssh process remains active in the background. What I expect to happen is this:

  1. Execute the SSH command in the background so that the script returns immediately.
  2. The SSH command should connect to the host, execute the sh -s ... commands and immediately return.
  3. The SSH process from step 1 should end

Can someone help me get this behavior? Note that the machine I execute all of this on has bash, and newer version of sh. But the remote SSH host does not have bash, only a very old version of sh. Not sure if that will matter, but thought I'd share anyway.

EDIT 1

I tried this as well but the behavior is the same:

cat ./do_sync | ssh "root@$ip" &

EDIT: Realized this is invalid, because I omitted the nohup part, but this ended up having the same blocking behavior:

cat ./do_sync | ssh "root@$ip" "nohup sh -s"

EDIT 2

Tried this as well, still blocks the SSH connection from disconnecting:

commands="$(cat ./do_sync)"
ssh "root@$ip" "nohup sh -c $commands"

In this case for some reason sh -s didn't work at all.

  • The sh -s process may not actually read the whole script to the end as soon as possibly, but only to the point it needs to to run it. This keeps the connection open. I'm assuming that when it reaches the end of input, the connection is terminated. Transferring the script to the remote host and running it there would alleviate this. – Kusalananda Dec 03 '19 at 19:13
  • the script changes constantly. i cant do that. – void.pointer Dec 03 '19 at 19:40
  • What would be wrong with transferring the script to a file and running it on the remote system? The next time you run the command, you would transfer a new copy of the script. – Kusalananda Dec 03 '19 at 19:50
  • How should I transfer a copy of the script? I do not have scp on the remote host and it cannot be added. – void.pointer Dec 03 '19 at 19:54
  • ssh remote 'cat >./do_sync && nohup sh ./do_sync &' <./do_sync or something (untested) – Kusalananda Dec 03 '19 at 20:00
  • cat ./do_sync | ssh "root@$ip" "cat > /do_sync && chmod 777 /do_sync && nohup /do_sync" this still blocks, now I'm really confused.... – void.pointer Dec 03 '19 at 20:06
  • Where's that final & in your last command? Not there. – Kusalananda Dec 03 '19 at 20:07
  • The sh in BusyBox is of course the Almquist shell, as the BusyBox doco tells you. Confusing to people who erroneously think that the Bourne Again shell is definitive, but not actually the problem here. – JdeBP Dec 03 '19 at 20:47

2 Answers2

2

The trick with nohup sometimes is to redirect all three standard streams. This should work for you:

cat ./do_sync | ssh root@ip "cat > /tmp/do_sync && chmod 777 /tmp/do_sync ;  nohup /tmp/do_sync 2>/dev/null >/dev/null </dev/null &"

But without the redirections for nohup, it will block.

  • I had almost exactly the same issue, except that my new process was launched inside a script I called from ssh. in local tests it was fine, only blocked when I called the script from SSH. This is how I fixed it in my script:

    nohup ./longrunningscript.sh >/dev/null 2>/dev/null </dev/null &

    – panschk Jun 28 '21 at 11:26
0

An alternative approach would be

cat do_sync | ssh "root@ip" 'nohup sh -s'

I'm assuming the effect you see is because you're executing ./do_sync in the background. It only appears that the process still hangs. Unless you're actually seeing an open connection?

Bram
  • 2,459
  • In this case the SSH process still did not exit. – void.pointer Dec 03 '19 at 19:49
  • Did you try as is or with the extra & in the edit to your question? Also could it be a command in the do_sync command that is actually still running on the target machine? – Bram Dec 03 '19 at 19:50
  • My edit was flawed, and not related to your answer (we were apparently thinking of a similar approach at the same time). Mine is incorrect because the script runs commands that block for a long time. So the invocation of the script contents itself must be done in the background. In a way I'm trying to treat the script as a function, and run that function in the background. I did try yours and it still didn't exit. I need to use & when I invoke ssh because I don't want to wait for the SSH connection to establish. – void.pointer Dec 03 '19 at 19:54
  • Your command actually causes my terminal to block. Not sure why. – void.pointer Dec 03 '19 at 19:55
  • your terminal blocks because it is waiting for the nohup'ed command to complete. The & you add is sending the local command (the ssh connection) to the background it does not run the remote command in the background. – Bram Dec 03 '19 at 20:05
  • Right, I'm still expecting the SSH command to only block long enough to connect and execute the nohup, at which point it should return and disconnect. – void.pointer Dec 03 '19 at 20:07
  • The right answer involves the answers to https://unix.stackexchange.com/q/493159/5132 and the self-contradiction in what the questioner is trying to do. – JdeBP Dec 03 '19 at 20:58