36

Normally, if you pass a command to ssh like so

ssh me@example.com 'some-command.sh'

You get a non-interactive session, and ssh exits as soon as the command (or script, or whatever) is run. How can I get an interactive session, and yet run a command that I've specified from my local machine. For instance, I'd like to be able to open screen and restart a specific screen session:

ssh me@example.com 'screen -r 12345'

but this is not allowed, returning the error "Must be connected to a terminal." which I presume means essentially "must call this command from an interactive shell".

As another example, I use a ton of machines at work that often require me to use a shared account to have rights to do certain things (yeah I know: bad idea but don't blame me, I didn't set things up that way), and they usually have ksh as the default shell. I'd like to log in, switch to bash (or zsh), and source my own account's .bash_profile (or .zshrc). This would be easy if I could establish an interactive ssh session and pass a command to the remote machine to run upon login.

I have a very kludgey (and untested) solution in mind that I will post, but I'm hoping someone knows a better way.

UPDATE: for those who didn't realize this, I'm not planning to do all this by hand, so telling me to open an interactive session and then do it by hand doesn't actually solve anything.

2nd UPDATE: To attempt once again to clarify: I'm trying to run (arbitrary) commands on the server (programmatically specified on the client) but then have an interactive session open that is affected by anything done by those programmatic commands.

2
  • echo "command" | ssh user@remote_host Jan 22, 2015 at 11:11
  • 2
    Did you miss the "without exiting" part of the question? I'm quite sure this will exit after the command finishes.
    – iconoclast
    Jan 22, 2015 at 15:02

8 Answers 8

29

You can try the following command to start up bash and source your own profile when you ssh:

ssh  -t hostname "bash --rcfile ~user/.bashrc"
2
  • 4
    +1. The -t switch fixes the questioner's problem with screen as well.
    – Patches
    Mar 24, 2011 at 2:00
  • 3
    Can this be used with arbitrary commands, without closing the connection? If I try ssh -t www.dev "echo 'hi there'", the connection is immediately closed after the command is executed.
    – iconoclast
    Mar 26, 2013 at 19:50
13

Building on dogbane's answer, a complete solution looks like:

ssh -t user@server 'cd /a/great/place; bash'

Here I use -t to force the allocation of a pseudo-terminal, which is required for an interactive shell. Then I execute two commands on the server: first the thing I wanted to do prior to opening the interactive shell (in my case, changing directory to a specific folder), and then the interactive shell itself. bash sees that it has a pseudo-terminal and responds interactively.

The single quotes ensure the entire thing is passed to the remote server as the command to be run by your default shell.

Thanks again to dogbane for providing the necessary clue with -t. I used to solve this problem with expect, which is definitely killing a mouse with a cannon. (:

2

Try this solution.

echo "command" | ssh user@remote_host

The login is interactive and your command is passed as if you typed it on the interactive command line. The session terminates as if you had typed

ssh user@remote_host 'command'
2
  • 3
    If the session terminates after the command is complete, then this does not answer the question. The whole point of the command is to be left with an interactive session after the command is executed, not merely to send commands to servers through ssh.
    – iconoclast
    Mar 26, 2013 at 19:31
  • This is at least good for simulating an interactve for the command to execute in, without using -t or your own bash file. +1 Jan 22, 2015 at 11:10
0

Use ssh -X to use termIO cmds.

Also - you can chain your cmds like "ssh 'source ~/.bashrc && cd && do '"

2
  • but after the whole chain is done, I don't have an interactive session remaining, right? It still closes, right?
    – iconoclast
    Apr 3, 2011 at 16:15
  • And would you care to elaborate on the termIO solution?
    – iconoclast
    Apr 3, 2011 at 16:15
0

why not install detach on the remote system and use:

ssh -t user@example.com "/home/user/bin/detach ls"
3
  • will this run 'ls' and THEN leave me with an interactive session? What if, instead of 'ls', I run 'source .somefile' to get some aliases and functions. Will they be available in my interactive session, or will it have been run under a different session?
    – iconoclast
    Dec 19, 2011 at 15:59
  • No, due to detach, ls doesn't keep the session open and will disconnect without printing the output of ls but it'll still run.
    – Dan D.
    Dec 22, 2011 at 8:25
  • I'm trying to run (arbitrary) commands on the server (programmatically specified on the client) but then have an interactive session open that is affected by anything done by those programmatic commands. So if I understand you correctly, this doesn't help me.
    – iconoclast
    Dec 23, 2011 at 18:03
0

laggingreflex's answer is close... I'd change it as follows:

echo "command\n$(cat -)" | ssh user@remote_host

Unfortunately, you're not likely to like the way that works, 'cause "cat" buffers the lines it writes to stdout... If we create a script called "echo-cat" that looks something like this:

{
  echo "${@}"
 #cat buffers & won't flush to stdout immediately
 #cat -
  IFS='\n'
  while read line
  do
        echo "${line}"
  done
}

we'll get the same result without the buffering:

echo-cat "command" | ssh user@remote_host

That'll probably get you a lot closer to your objective...

0

This is kludgey, and untested, but I think it should work.

Create a script named (e.g.) remote-starter that takes a quoted argument after a user@host argument:

remote-starter user@example.com 'some-command.sh arg1 arg2'

This script should first save the quoted command (without quotes) in file named (e.g.) .onetime on the remote machine, and then run a regular ssh command, this time not passing any command to be run on the remote machine. (If running ssh user@example.com from within a script, it may work to run exec ssh user@example.com.)

For this to work, the remote machine must source .onetime from its .bash_profile or .zshrc or whatever. After running .onetime, it should delete .onetime, so the file is not run the following time you do a regular login.

0

Here is the closest I've come to making this work without writing the remote-start script mentioned in the other answer:

ssh -t server_name "tmux new-session -s session_name 'bash --rcfile <(echo \". ~/.brandon; echo run_an_arbitrary_command_here_not_echo\")'"

In this case I'm logging in as the ubuntu user and sourcing a file with my own functions in it. I was not able to switch user automatically, but I can for example add an alias to ~/.brandon that switches user almost effortlessly, with an alias named ,. I suppose I could have added a hook script in ``~/.brandonthat would change user when creating the prompt, if Bash can do anything like Zsh'sprecmd` function.

And of course I could replace ~/.brandon with /home/users/brandon/.bashrc or whatever, but this server doesn't have individual accounts.

(No, I didn't set the server up to have shared accounts—I'm well aware of the fact that it's a bad idea.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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