333

I often have to login to one of several servers and go to one of several directories on those machines. Currently I do something of this sort:

localhost ~]$ ssh somehost

Welcome to somehost!

somehost ~]$ cd /some/directory/somewhere/named/Foo
somehost Foo]$ 

I have scripts that can determine which host and which directory I need to get into but I cannot figure out a way to do this:

localhost ~]$ go_to_dir Foo

Welcome to somehost!

somehost Foo]$

Is there an easy, clever or any way to do this?

Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
Frosty
  • 6,213
  • 3
  • 24
  • 20

15 Answers15

551

You can do the following:

ssh -t xxx.xxx.xxx.xxx "cd /directory_wanted ; bash --login"

This way, you will get a login shell right on the directory_wanted.


Explanation

-t Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services.

Multiple -t options force tty allocation, even if ssh has no local tty.

  • If you don't use -t then no prompt will appear.
  • If you don't add ; bash then the connection will get closed and return control to your local machine
  • If you don't add bash --login then it will not use your configs because its not a login shell
Weston Ganger
  • 6,324
  • 4
  • 41
  • 39
rogeriopvl
  • 51,659
  • 8
  • 55
  • 58
  • Executing the shell at the end was the final piece of the puzzle. Thank you. – Frosty Mar 09 '09 at 15:08
  • 25
    in my case -t the missing part – Mathieu Jan 30 '12 at 09:52
  • 4
    When using this approach the .bash_profile is not read, anyone knows why? – Filipe Felisbino Nov 21 '12 at 18:06
  • 1
    @filipenf that's because when you launch bash "manualy" only .bashrc is loaded. – rogeriopvl Nov 25 '12 at 22:46
  • 10
    I had to do this: `ssh -t xxx.xxx.xxx.xxx "cd /directory_wanted && exec \$SHELL"` – abc123 May 06 '13 at 21:03
  • 1
    `"cd /directory_wanted && bash"` is better in case when `/directory_wanted` does not exist. – ks1322 Nov 07 '13 at 08:43
  • 49
    You'll usually want a login shell: `ssh -t example.com "cd /foo/bar; exec \$SHELL -l"` – christianbundy Apr 28 '14 at 03:54
  • 12
    Just wanted to link [change directory automatically on ssh login - Server Fault](http://serverfault.com/a/215051); and from there paste this command ( which is a version of the one by @christianbundy ): `ssh server -t "cd /my/remote/directory; bash --login"` – sdaau Jun 22 '14 at 13:23
  • for me, ssh -t xxx.xxx.xxx.xxx "cd /directory_wanted && $SHELL" works fine – Pejvan Aug 26 '14 at 08:54
  • When I do this I end up without a prompt. Bash still works fine but I like a prompt that shows the working directory. I'm SSHing in from zsh. Login shell doesn't help – light24bulbs Aug 12 '15 at 03:24
  • Careful @Pejvan - you're trying to use the _local_ value of `$SHELL` on the _remote_ machine there! – PJSCopeland Aug 02 '16 at 23:27
  • If you have the host specified in .ssh/config then just `ssh [your host] -t "cd [your directory]; bash"` – flaudre Apr 16 '17 at 07:02
  • where should `.ssh` folder located under `/directory_wanted ` ? – alper Jul 23 '21 at 15:13
  • It is important to note that by the time the commands execute, `.bashrc` has not initialized yet, so many of your variables or presets might not be ready at this time – Domi Nov 25 '22 at 07:50
83

You could add

cd /some/directory/somewhere/named/Foo

to your .bashrc file (or .profile or whatever you call it) at the other host. That way, no matter what you do or where you ssh from, whenever you log onto that server, it will cd to the proper directory for you, and all you have to do is use ssh like normal.

Of curse, rogeriopvl's solution works too, but it's a tad bit more verbose, and you have to remember to do it every time (unless you make an alias) so it seems a bit less "fun".

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • 4
    +1, this looks more suitable if you need constant directory instead of making ssh command longer remembering everytime to which directory you are going to move when you connect to X machine – Tebe May 04 '14 at 21:49
  • Not proper when changing flexibly – Lewis Chan Apr 18 '20 at 02:31
68

My preferred approach is using the SSH config file (described below), but there are a few possible solutions depending on your usages.

Command Line Arguments

I think the best answer for this approach is christianbundy's reply to the accepted answer:

ssh -t example.com "cd /foo/bar; exec \$SHELL -l"

Using double quotes will allow you to use variables from your local machine, unless they are escaped (as $SHELL is here). Alternatively, you can use single quotes, and all of the variables you use will be the ones from the target machine:

ssh -t example.com 'cd /foo/bar; exec $SHELL -l'

Bash Function

You can simplify the command by wrapping it in a bash function. Let's say you just want to type this:

sshcd example.com /foo/bar

You can make this work by adding this to your ~/.bashrc:

sshcd () { ssh -t "$1" "cd \"$2\"; exec \$SHELL -l"; }

If you are using a variable that exists on the remote machine for the directory, be sure to escape it or put it in single quotes. For example, this will cd to the directory that is stored in the JBOSS_HOME variable on the remote machine:

sshcd example.com \$JBOSS_HOME

SSH Config File

If you'd like to see this behavior all the time for specific (or any) hosts with the normal ssh command without having to use extra command line arguments, you can set the RequestTTY and RemoteCommand options in your ssh config file.

For example, I'd like to type only this command:

ssh qaapps18

but want it to always behave like this command:

ssh -t qaapps18 'cd $JBOSS_HOME; exec $SHELL'

So I added this to my ~/.ssh/config file:

Host *apps*
    RequestTTY yes
    RemoteCommand cd $JBOSS_HOME; exec $SHELL

Now this rule applies to any host with "apps" in its hostname.

For more information, see http://man7.org/linux/man-pages/man5/ssh_config.5.html

Drew Nutter
  • 955
  • 8
  • 14
  • 4
    `RequestTTY` combined with `RemoteCommand` was exactly what I needed, thank you. – johnpitchko Jul 22 '21 at 16:40
  • this works better if you has a different shell like zsh – farid g. Oct 12 '22 at 06:49
  • ```zsh:1: command not found: gs``` Does anyone have any idea reagarding to how I could make the shell that I am starting through ssh aware of the aliases on the remote machine? I tried using `source ~/.zshrc` as my first command in the double-quoted string that we pass to `ssh -t` (ie: `ssh -t my-remote.com "source ~/.zshrc; g; gs; exec $SHELL -l"`) but to no avail. Thanks! – M.Ionut Feb 28 '23 at 12:19
  • I also tried this https://unix.stackexchange.com/questions/425319/how-do-i-execute-a-remote-alias-over-an-ssh but it does not work for `zsh` – M.Ionut Feb 28 '23 at 12:26
23

I've created a tool to SSH and CD into a server consecutively – aptly named sshcd. For the example you've given, you'd simply use:

sshcd somehost:/some/directory/somewhere/named/Foo

Let me know if you have any questions or problems!

christianbundy
  • 666
  • 9
  • 21
  • 1
    Would be cool if you could define a new config in ~/.ssh/config and read it from there ;) – Alexar Jan 28 '15 at 04:24
19

Based on additions to @rogeriopvl's answer, I suggest the following:

ssh -t xxx.xxx.xxx.xxx "cd /directory_wanted && bash"

Chaining commands by && will make the next command run only when the previous one was successful (as opposed to using ;, which executes commands sequentially). This is particularly useful when needing to cd to a directory performing the command.

Imagine doing the following:

/home/me$ cd /usr/share/teminal; rm -R *

The directory teminal doesn't exist, which causes you to stay in the home directory and remove all the files in there with the following command.

If you use &&:

/home/me$ cd /usr/share/teminal && rm -R *

The command will fail after not finding the directory.

Bas Peeters
  • 3,269
  • 4
  • 33
  • 49
4

In my very specific case, I just wanted to execute a command in a remote host, inside a specific directory from a Jenkins slave machine:

ssh myuser@mydomain
cd /home/myuser/somedir 
./commandThatMustBeRunInside_somedir
exit

But my machine couldn't perform the ssh (it couldn't allocate a pseudo-tty I suppose) and kept me giving the following error:

Pseudo-terminal will not be allocated because stdin is not a terminal

I could get around this issue passing "cd to dir + my command" as a parameter of the ssh command (to not have to allocate a Pseudo-terminal) and by passing the option -T to explicitly tell to the ssh command that I didn't need pseudo-terminal allocation.

ssh -T myuser@mydomain "cd /home/myuser/somedir; ./commandThatMustBeRunInside_somedir"
Mauricio Reis
  • 319
  • 3
  • 9
3

going one step further with the -t idea. I keep a set of scripts calling the one below to go to specific places in my frequently visited hosts. I keep them all in ~/bin and keep that directory in my path.

#!/bin/bash

# does ssh session switching to particular directory
# $1, hostname from config file 
# $2, directory to move to after login
# can save this as say 'con' then
# make another script calling this one, e.g.
# con myhost repos/i2c

ssh -t $1 "cd $2; exec \$SHELL --login"
DKebler
  • 1,216
  • 1
  • 15
  • 27
3

I use the environment variable CDPATH

Eddy
  • 1,862
  • 12
  • 12
  • Useful only if I was interested in one directory per machine. I need a way to pass information to the remote machine. Roger's solution does just that. – Frosty Mar 09 '09 at 15:09
3

My answer may differ from what you really want, but I write here as may be useful for some people. In my solution you have to enter into the directory once and then every new ssh session goes to the same dir (after the first logout).

How to ssh to the same directory you have been in your last login. (I assume you use bash on the remote node.)

Add this line to your ~/.bash_logout on the remote node(!):

echo $PWD > ~/.bash_lastpwd

and these lines to the ~/.bashrc file (still on the remote node!)

if [ -f ~/.bash_lastpwd ]; then
    cd $(cat ~/.bash_lastpwd)
fi

This way you save your current path on every logout and .bashrc put you into that directory after login.

ps: You can tweak it further like using the SSH_CLIENT variable to decide to go into that directory or not, so you can differentiate between local logins and ssh or even between different ssh clients.

redseven
  • 849
  • 6
  • 11
  • This is great if you want to restore the state from your last session so it's like you have one continuous session that you log in and out of. But I think your second sentence is misleading, "enter into the directory once and then every new ssh session goes to the same dir (after the first logout)." It won't always visit the same directory from the first logout. It will visit whatever directory you were in at the last logout, which may change often. – Drew Nutter Mar 04 '21 at 22:38
  • It's not only useful if you have one continuous session. It works many sessions as well, but indeed it works the best if wish to work all your session in the same dir. Suggest a change for that sentence. I don't know how to write it short and clean. – redseven Mar 05 '21 at 20:57
1

Another way of going to directly after logging in is create "Alias". When you login into your system just type that alias and you will be in that directory.

Example : Alias = myfolder '/var/www/Folder'

After you log in to your system type that alias (this works from any part of the system)
this command if not in bashrc will work for current session. So you can also add this alias to bashrc to use that in future

$ myfolder => takes you to that folder

insomiac
  • 5,648
  • 8
  • 45
  • 73
0

I know this has been answered ages ago but I found the question while trying to incorporate an ssh login in a bash script and once logged in run a few commands and log back out and continue with the bash script. The simplest way I found which hasnt been mentioned elsewhere because it is so trivial is to do this.

#!/bin/bash

sshpass -p "password" ssh user@server 'cd /path/to/dir;somecommand;someothercommand;exit;'
Hani Umer
  • 21
  • 4
0

Connect With User

In case if you don't know this, you can use this to connect by specifying both user and host
ssh -t <user>@<Host domain / IP> "cd /path/to/directory; bash --login"

Example: ssh -t admin@test.com "cd public_html; bash --login"

You can also append the commands to be executed on every login by appending it in the double quotes with a ; before each command

ABHi
  • 404
  • 4
  • 8
0

Unfortunately, the suggested solution (of @rogeriopvl) doesn't work when you use multiple hops, so I found another one. On remote machine add into ~/.bashrc the following:

[ "x$CDTO" != "x" ] && cd $CDTO

This allows you to specify the desired target directory on command line in this way:

ssh -t host1 ssh -t host2 "CDTO=/desired_directory exec bash --login"

Sure, this way can be used for a single hop too.

This solution can be combined with the usefull tip of @redseven for greater flexibilty (if no $CDTO, go to saved directory, if exists).

-2

SSH itself provides a means of communication, it does not know anything about directories. Since you can specify which remote command to execute (this is - by default - your shell), I'd start there.

Samsquanch
  • 8,866
  • 12
  • 50
  • 89
Jan Jungnickel
  • 2,084
  • 14
  • 13
-7

simply modify your home with the command: usermod -d /newhome username

evandrix
  • 6,041
  • 4
  • 27
  • 38