With ssh, how can you run a command on the remote machine without exiting?

30

8

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.

iconoclast

Posted 2011-03-23T16:01:44.990

Reputation: 2 752

echo "command" | ssh user@remote_host – laggingreflex – 2015-01-22T11:11:20.347

2Did you miss the "without exiting" part of the question? I'm quite sure this will exit after the command finishes. – iconoclast – 2015-01-22T15:02:56.790

Answers

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.

iconoclast

Posted 2011-03-23T16:01:44.990

Reputation: 2 752

27

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"

dogbane

Posted 2011-03-23T16:01:44.990

Reputation: 3 771

4+1. The -t switch fixes the questioner's problem with screen as well. – Patches – 2011-03-24T02:00:37.263

3Can 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 – 2013-03-26T19:50:28.103

11

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. (:

user1179239

Posted 2011-03-23T16:01:44.990

Reputation: 220

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'

user210540

Posted 2011-03-23T16:01:44.990

Reputation: 21

This is at least good for simulating an interactve for the command to execute in, without using -t or your own bash file. +1 – laggingreflex – 2015-01-22T11:10:35.147

3If 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 – 2013-03-26T19:31:46.803

0

Use ssh -X to use termIO cmds.

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

ethrbunny

Posted 2011-03-23T16:01:44.990

Reputation: 347

but after the whole chain is done, I don't have an interactive session remaining, right? It still closes, right? – iconoclast – 2011-04-03T16:15:12.677

And would you care to elaborate on the termIO solution? – iconoclast – 2011-04-03T16:15:39.243

0

why not install detach on the remote system and use:

ssh -t user@example.com "/home/user/bin/detach ls"

Dan D.

Posted 2011-03-23T16:01:44.990

Reputation: 5 138

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 – 2011-12-19T15:59:10.587

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. – 2011-12-22T08:25:17.350

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 – 2011-12-23T18:03:51.110

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...

Bill

Posted 2011-03-23T16:01:44.990

Reputation: 1