119

I'm trying to get ssh to automatically change to a particular directory when I log in. I tried to get that behaviour working using the following directives in ~/.ssh/config:

Host example.net
LocalCommand "cd web"

but whenever I log in, I see the following:

/bin/bash: cd web: No such file or directory

although though there is definitely a web folder in my home directory. Even using an absolute path gives the same message. To be clear, if I type cd web after logging in I get to the right folder.

What am I missing here?

EDIT:

Different combinations of quotes/absolute paths give different error messages:

LocalCommand "cd web"
/bin/bash: cd web: No such file or directory

LocalCommand cd web
/bin/bash: line 0: cd: web: No such file or directory

LocalCommand cd /home/gareth/web
/bin/bash: line 0: cd: /home/gareth/web: Input/output error

This makes me think that the quotes shouldn't be there, and that there's another error happening.

sobi3ch
  • 873
  • 1
  • 7
  • 11
Gareth
  • 1,416
  • 2
  • 11
  • 12

12 Answers12

93

This works:

ssh server -t "cd /my/remote/directory; bash --login"

To create a directory if it doesn't exist:

ssh server -t "mkdir -p newfolder; cd ~/newfolder; pwd; bash --login"

If you don't add bash to the end of path then you exit after the cd comand runs. And If you don't add --login then your ~/.profile isn't sourced.

rcoup
  • 167
  • 1
  • 8
Vladislav Lezhnev
  • 1,039
  • 1
  • 7
  • 2
66
  1. Login to your box
  2. Edit ~/.bash_profile
  3. On the end of the file add cd /path/to/your/destination
  4. Save it & exit
  5. Logout from the box
  6. Login again and then you should land on /path/to/your/destination

Note (Dec 2021): As @Matthias points out on some machines you may need need to append your command to ~/.bashrc instead of to ~/.bash_profile.

sobi3ch
  • 873
  • 1
  • 7
  • 11
56

cd is a shell builtin. LocalCommand is executed as:

/bin/sh -c <localcommand>

What you're looking to do can't really be accomplished via SSH; you need to modify the shell in some way, e.g. via bashrc/bash_profile.

<Editing almost a decade later...>

LocalCommand isn't what you want, anyway. That's run on your machine.

You want RemoteCommand. Something like this worked for me:

Host example.net
  RemoteCommand cd / && exec bash --login
  RequestTTY yes
BMDan
  • 7,249
  • 2
  • 23
  • 34
  • 3
    Yep, just wanted to mention to same. You can put the `cd` command in `~/.bashrc` at the remote server instead. – vdboor Aug 05 '10 at 16:00
  • That's annoying. As I mentioned in another comment, the server has a number of hostnames and I wanted to have different behaviour based on which was used. I guess it's not possible to determine which was used from .bashrc? – Gareth Aug 05 '10 at 16:15
  • It's possible, just probably not advisable. Something like replacing ssh with a small shell script or alias that passes the host name as a variable to be exported (a la "ssh -t user@host 'export connhostname=host; bash --login'"). But you're starting to get into very strange territory, indeed. Perhaps a better question is, WHY do you want this behavior? – BMDan Aug 05 '10 at 17:50
  • It's not really that big a deal to be honest. I'm just in the situation where the vast majority of the time I log into this server I head straight to one of two directories (depending on which host I'm using) – Gareth Aug 06 '10 at 07:32
  • 2
    What is `RequestTTY yes` for? – reynoldsnlp Sep 08 '21 at 18:22
  • the exec bash --login part is awesome. Without that I get logged out immediately. – John Jiang Oct 08 '21 at 21:42
  • Works like a charm. Synology NAS / DSM uses the `~/.bashrc`. – Kees C. Bakker Dec 30 '21 at 05:24
5

Have you enabled this directive in your ssh config?

PermitLocalCommand yes

The default for that is no, in which case your LocalCommand directive would be ignored.

Alternatively, have you tried adding the command to your .bashrc file?

EEAA
  • 109,363
  • 18
  • 175
  • 245
  • That directive is set, yes (and I assume I wouldn't see the error message shown if it wasn't). The problem with using .bashrc is that the server has different host names, and I'd like different host names to translate to different starting directories – Gareth Aug 05 '10 at 14:57
  • Unless each host name has a different IP address, there would be no way for the server to know which host name you requested. While HTTP requests provide a friendly Host: header to identify the requested host name, SSH connections do not. – Fosco Aug 05 '10 at 19:42
4

More robust solution for the case when you need to ssh and override default .bashrc file. This is useful in cases when remote server environment has multiple docroots and used by multiple users.

alias ssh_myserver='ssh server_name -t "echo cd /path/to/desired/dir>/tmp/.bashrc_tmp; bash --rcfile /tmp/.bashrc_tmp"'

More detailed:

  1. First command creates .bashrc_tmp file in /tmp directory on the remote server with a content cd /path/to/dir
  2. Next command executes bash with config file specified in step 1. This allows to switch to desired dir and suppress default .bashrc.
  3. This whole command is wrapped as an alias, so on ssh client command prompt it can be called as ssh_myserver
slm
  • 7,615
  • 16
  • 56
  • 76
Alex Skrypnyk
  • 149
  • 2
  • 4
4

So I have searched a lot of websites (stackoverflow, this one) but did not find what I wanted. I ended up creating my own shell script. I am pasting it here. Also you can copy it a directory in the $PATH.

#!/bin/bash
ssh -t <username@hostname> "cd ~/$1; exec \$SHELL --login"

So after this. I do:

connect <foldername>

Note: You may need to log out and log in again after changing the path variable

kasperd
  • 30,455
  • 17
  • 76
  • 124
Aryan
  • 49
  • 1
  • 2
  • I prefer this to the previous suggestion because '$SHELL' is always valid, while 'bash' may not be. Also the use of 'exec' is a nice touch. – Dave Aug 16 '17 at 02:24
  • A further refinement would to be ensure 'cd' is successful - "cd ~/$1 && exec ...' – Dave Aug 16 '17 at 02:27
3

In your ~/.ssh/config:

LocalCommand echo '/home/%r/some/subdir' > /home/%r/.ssh/ssh_cd

At the end of your ~/.bashrc:

if [[ -f $HOME/.ssh/ssh_cd ]]
then
    cd $(<$HOME/.ssh/ssh_cd)
    # uncomment the line below and the file will be removed so the cd won't work
    # unless the file is regenerated since you may not want this to operate for
    # non-ssh logins or for ssh logins that you want to function differently
    # rm $HOME/.ssh/ssh_cd
fi

I tried doing this using variable passing, including with an exported variable, but these commands get run in different shells.

When testing what you were trying to do I didn't get an error when I used the unquoted absolute path, by the way. I added ; pwd at the end of the command and the correct directory is displayed, however the directory I end up in is ~. There are no cd commands in my shell startup files. I tried putting a different cd somedir; pwd in ~/.ssh/rc (with the other still in place). The config command is executed before the motd is issued and the rc command is issued afterwards, but before the shell startup files are sourced. So again, it's happening in a different shell.

Try the passing-by-file technique and let me know if it works for you.

Dennis Williamson
  • 62,149
  • 16
  • 116
  • 151
2

Have you tried it without the quotes around it? The only examples I've seen don't have them so with them it could be trying to execute cd\ web as a command.

James L
  • 6,025
  • 1
  • 22
  • 26
2

You could also try this, with the option -t:

ssh server -t "cd /my/remote/directory; bash"
kenorb
  • 6,499
  • 2
  • 46
  • 54
0

Maybe you need to create ~/.bash_profile although you already have a ~/.bashrc.

On my debian system the ~/.bashrc was not executed upon login with sshpass.

Since I added cd directory to the newly created ~/.bash_profile it worked fine.

bomben
  • 115
  • 9
0

I use the following in .ssh/config:

  RemoteCommand cd ~/mydir;bash
  RequestTTY force
sluge
  • 119
  • 3
0

Try using RemoteCommand instead, e.g.

Host myhost
  HostName IP
  User ubuntu
  IdentityFile ~/.ssh/id_rsa
  RemoteCommand cd web; $SHELL -il

RemoteCommand: Specifies a command to execute on the remote machine after successfully connecting to the server. (man ssh_config)

kenorb
  • 6,499
  • 2
  • 46
  • 54