When working with SSH connections, we often face a binary choice: either get a standard interactive shell in the default environment, or execute a single remote command non-interactively. Many developers need something in between - an interactive session that executes specific initialization commands first.
The typical workarounds have limitations:
ssh user@host "cd /project; bash --login" # Loses some shell features
ssh -t user@host "source env.sh; bash" # May break session control
Neither properly preserves the full interactive shell experience while allowing pre-session commands.
1. Forced Command with Environment Preservation
This approach maintains full shell functionality:
ssh -t user@host '
cd /your/target/directory
export CUSTOM_VAR=value
exec bash --login
'
2. SSH Config with LocalCommand
Add to ~/.ssh/config:
Host myserver
HostName server.example.com
User developer
LocalCommand ssh -t %h "cd /projects/%(n); exec bash --login"
3. Dynamic .bashrc Modification
Create a wrapper script that temporarily modifies .bashrc:
function ssh-pre() {
local cmd="$(printf '%q ' "$@")"
ssh -t $1 "echo 'eval $cmd' >> ~/.bashrc.tmp &&
trap 'rm ~/.bashrc.tmp' EXIT &&
bash --rcfile ~/.bashrc.tmp -i"
}
For complex environments:
ssh -t dbadmin@prod-db '
. /etc/database-profile
cd /var/lib/pgsql
exec bash --norc --noprofile -i'
- Always use
-tfor pseudo-terminal allocation exec bashreplaces the current shell process- Consider SSH ControlMaster for multiple commands
Many developers face this common scenario: you need to SSH into a server but want certain commands to execute automatically before the interactive shell starts. Standard solutions like .bashrc modifications aren't ideal when you need session-specific initialization.
The obvious approach using ssh "commands; bash" fails because:
- Environment variables set in the command sequence don't persist
- The shell doesn't load your normal profile/rc files
- Terminal settings and job control behave differently
1. SSH RemoteCommand with Login Shell
Modern OpenSSH (7.6+) supports the RemoteCommand option:
ssh -t user@host \
-o RemoteCommand="cd /project/dir && export ENV_VAR=value; exec \$SHELL -l"
Key points:
-tforces pseudo-terminal allocationexec \$SHELL -lstarts a proper login shell after commands- Environment variables persist because we're in the same process
2. SSH Config with Local Command Sequences
For reusable setups, add to ~/.ssh/config:
Host myserver
HostName server.example.com
User devuser
RequestTTY yes
RemoteCommand cd /projects/current && export DEBUG=1 && exec bash -l
3. Environment Forwarding Alternative
When you just need environment variables:
ssh -o SendEnv=MY_VAR user@host
# Then in remote ~/.ssh/environment:
MY_VAR=value
Requires PermitUserEnvironment yes in server's sshd_config.
For development environments where you switch between projects:
function ssh-project() {
local project_dir="/projects/$1"
ssh -t user@host \
-o RemoteCommand="cd $project_dir && source envsetup.sh && exec \$SHELL -l"
}
# Usage:
ssh-project my_current_project
If things don't work as expected:
- Check
echo $0- should show-bash(login shell) - Verify
ssh -Vshows at least OpenSSH 7.6 - Test with simple commands first (
echo test)