3

Imagine we have a long command sleep 10 (for instance). We would like to execute it on another server using python (the ssh library paramiko to be specific).

I need a 1 line command that starts the command, prints the PID of the command, and then waits for it to finish and finally returns the exit status of the command.

What I've tried so far:

bash -c "echo $BASHPID ; exec sleep 10" ; echo $?

This prints the PID of the shell, then calls exec on the long command, and then waits and prints the exit status. The problem is $BASHPID prints the PID of the outer bash shell (possibly indicating calling bash -c cmd doesn't actually spawn a full new shell?).

If I call the above command in three lines, it works.

bash
echo $BASHPID ; exec sleep 10
echo $?

Any attempt using subshells hasn't worked for me either.

echo $(echo $BASHPID ; exec sleep 10) ; echo $?

This works, but the subshell pipes all of its output to echo, and echo prints it all at once, meaning the $BASHPID doesn't get print until after the sleep finishes. The PID must be print immediately.

  • 3
    tried single-quoting it? double-quotes allow the outer bash to interpolate variables. – Jeff Schaller Mar 10 '17 at 15:49
  • I think that's it.. :) – chub500 Mar 10 '17 at 15:53
4

When you run, for example:

bash -c "echo $BASHPID ; exec sleep 10"

or

echo $(echo $BASHPID ; exec sleep 10)

your current shell is interpolating the $BASHPID variable before the second bash (or subshell) sees it. The solution is to prevent the expansion of those variables by the current shell:

bash -c 'echo $BASHPID ; exec sleep 10'
4

That's a shell command you run over ssh already (interpreted by the login shell of the remote user), no need to start another shell on top of that. Assuming that shell is Bourne-like or csh-like:

echo "$$"; exec sleep 10

should be enough. No need to install bash on the remote host. ssh will also report the exit status of the remote command, no need to print it. But if you have to, you can do:

sleep 10 & echo "$!"; wait; echo "$?"

Not for csh-like shells as $? is $status instead there.

If you can't guarantee the login shell of the remote user be Bourne-like, you could do:

exec sh -c 'sleep 10 & echo "$!"; wait; echo "$?"'

That command should be compatible to shells of the Bourne, csh and rc families at least.

  • The second one worked for me (it is simpler than the one I was attempting). The only problem is there is latency when getting the PID because the syscall has to finish. I put in a quarter second timeout and it works great. – chub500 Mar 10 '17 at 23:06
  • As it turns out, this middle command (what I was using) doesn't work. I believe the return code from echo "$?" returns the code for wait, not from sleep 10. My attempt and the correct answer above actually do return the correct return code of the running subprocess. – chub500 Apr 11 '17 at 19:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.