0

I'm trying to execute a command in shell started over SSH, but keep the shell open. I know that normally the shell closes, so this needs to be worked-around, however I'm not very satisfied with the easy way to do that, like:

ssh server -t "TheCommand ; bash -i"

First thing is that the command is then visible in the ps output, also the command is executed before the bash subshell is launched and I would prefer to launch it in the final shell - the command is supposed to setup a custom environment for the shell, and if the environment is setup before launching the final (sub)shell, the environment variables can be overwritten by the RC profile (if the variable name is the same like a variable set in the RC).

I've found that I can use heredoc, so I came with this (solution #1):

ssh server -tt 3<<SCRIPT 4<&0 <&3
TheCommand
exec 3>&- <&4
SCRIPT

Unfortunately that does not work correctly: on the line

exec 3>&- <&4

the following error is reported:

-bash: 4: Bad file descriptor

and the shell remains open, however it cannot take any input (only Ctrl+C works to exit the ssh shell). Other than that, the script is executed and if I add ps ax | grep bash into the script, it shows:

15054 pts/15   Ss     0:00 -bash
15109 pts/15   S+     0:00 grep bash

which would be perfect, as it is the same as with a regular ssh login.

What is it supposed to do:

  1. Read the heredoc script onto the custom file descriptor 3 (because if the regular input descriptor is used, the shell terminates after the script is done).
  2. Dup the original stdin stream (0) into custom stream 4.
  3. Redirect the stdin to the fd 3 to read the heredoc script.
  4. At the end of the heredoc script, restore the input stream back to the original one (i.e. dup the stored fd 4 back into 0).

However it seems, that the restored stream is not valid for some reason and I don't know how to fix that, I tried many things (for example restoring to /dev/tty or $(tty), neither of which works - it does not report invalid stream and keeps the shell open, but I still cannot do anything there except Ctrl+C to exit).

I suspect that when I redirect the stdin to &3, the ssh or bash closes the standard stdin stream (or does not open/allocate it at all) so when I try to restore it back, it is invalid.

Is there any possibility to fix that? Because that would be my preferred solution.

I found one way to work this around like this (solution #2), by running the bash explicitly:

ssh server -t "bash -i 3<<SCRIPT 4<&0 <&3
TheCommand
exec 3>&- <&4
SCRIPT
"

That works, however it is not entirely ideal. One thing is, that it is not a login shell then (and it does not work with either bash -l or bash -l -i) and when running ps ax | grep bash in such shell, it gives the following:

15234 pts/15   Ss     0:00 bash -c bash -i 3<<SCRIPT 4<&0 <&3?TheCommand?exec 3>&- <&4?SCRIPT?
15262 pts/15   S      0:00 bash -i
15282 pts/15   S+     0:00 grep bash

which is not too good (the entire script is visible in the listing as with the simple solution at the beginning).

However, here the storing and restoring of the stdin (&0) works well. I'm wondering why it is working in the solution #2, but not in the solution #1, and if it can be fixed in the solution #1 somehow?

EDIT:

As some comments pointed out, I should better describe what I'm trying to solve.

In the principle, what exactly I'm trying to achieve is to develop a script that:

  • connects to SSH remote machine
  • changes the remote directory to location determined by the script
  • sets some environment variables in the remote shell (note that it might need to override variables coming from the profile or bashrc; and the profile/bashrc scripts need to be run to setup e.g. the command prompt etc.)
  • keep the ssh session open so that the operator can issue further commands afterwards (with the shell set up specifically)

One problem is the security issue (showing the entire command in the ps output), another one is when setting env variables before launching the final shell, they get overridden by the profile/bashrc (which contain some defaults).

So far my currently best solution is this:

ssh server -t "cd /ThePath ; exec \$SHELL -i 3<<ENV 4<&0 <&3
export THE_VARIABLE=TheValue
exec 3>&- <&4
ENV
"

This way the variable is set after the profile is loaded, so that seems to work. Also, the ps ax output is relatively fine:

17604 pts/15   Ss     0:00 /bin/bash -i
17654 pts/15   S+     0:00 grep bash

so it seems that the exec did the trick to some extent.

Is there any better way to do the above?

EmDroid
  • 5,918
  • 18
  • 18
  • 2
    I see a couple of close votes. I don't agree with them, but I would caution that this sounds very much like an [XY Problem](http://mywiki.wooledge.org/XyProblem). What are you *really* trying to do here? There's probably a better way. – ghoti Jan 06 '16 at 15:07
  • Not sure it's what you are looking for but maybe you can use [screen](http://www.thegeekstuff.com/2010/07/screen-command-examples/) – Duffydake Jan 06 '16 at 15:07
  • The problem with the first heredoc attempt is that the initial redirects are done on the local machine (because they are on the line with the heredoc) and not done on the remote machine (so the remote machine has no fd 4). The second attempt fixes that by quoting the entire argument to be run on the remote machine but moving the redirects off the first line in the first example should do that too. (But I'm not sure if that will help since that may not work at all.) – Etan Reisner Jan 06 '16 at 15:35
  • Use `expect` to drive the actual shell and then end with `interact`? – Etan Reisner Jan 06 '16 at 15:36
  • Yes, that seems to be the issue. However if I move the redirection, then the input is not redirected and the script is not loaded. So that it appears that inside of the shell started by ssh, the input is already coming redirected, and it is not possible to return it back. – EmDroid Jan 06 '16 at 15:55

0 Answers0