BASH and/or .BASHRC not working properly after SU or SSH login unless run bash command
If, in fact, your shell isn't bash
, you can try to change it like so:
usermod -s /bin/bash mikey
If /bin/bash is the location of bash
on that system.
Unable to switch to root user after ssh into the instance using shell script
"sudo su - & ${script}; "
expands to:
sudo su - & whoami && pwd && ...
First sudo su -
is run in the background. Then the command chain is executed.
sudo su -c ${script};
expands to:
sudo su -c whoami && pwd && ...
So first sudo su - whoami
is executed, which runs whoami
as root. Then if this command is successful, then pwd
is executed. As normal user.
It is utterly hard to correctly pass commands to execute on remote site using ssh. It is increasingly hard to do it with sudo su
- the command will be triple (or twice?) word splitted - one time by ssh, then by the shell, then by the shell run by sudo su
.
If you do not need interactive communication, it's best to use a here document with -s
shell option, something along (untested):
# DO NOT store commands to use in a variable.
# or if you do and you know what you are doing, properly quote it (printf "%q ") and run it via eval
script() {
set -euo pipefail
whoami
pwd
ls -la
whoami
mv "$buildVersion" "$buildPathToStore"
find "$buildPathToStore" | grep deb9
}
ssh ... "sudo bash -s" <<EOF
echo "Yay! anything here!"
echo "Note that here document delimiter is not quoted!"
$(
# safely import context to work with
# note how command substitution is executed on host side
declare -f script
# pass variables too!
declare -p buildVersion buildPathToStore buildPathToStore
)
script
EOF
Take bash startup file(s) with you into ssh?
In my ~/.ssh/config
I have an entry to choose the remote session file to use when log on in a server. In my case I use a specific rc
file instead of .bashrc
.
Host *
LocalCommand scp ~/.remote_bashrc %r@%n:/home/%r
RemoteCommand bash --rcfile "~/.remote_bashrc"
First, one copies the file to the remote.
Second, one uses it as shell session configuration.
Source bashrc in WSL in a non-interactive, non-login shell
Well, I've noodled on this on-and-off for several days to see if I could come up with a better solution. Nothing I can think of is optimal, but I think I ended up pretty close.
To restate/frame the problem:
You need a WSL distribution to run a certain interactive command (
keychain
) that loads its environment variables into the user's WSL/Bash session. This needs to happen to load the key intossh-agent
so thatwsl git
commands in IntelliJ will work with your plugin.keychain
will ask for a password for the key to be loaded if one is required.keychain
will output the environment variables needed forssh-agent
in a format that can be evaluated/sourced back into the Bash session.(Side-note: It's really lucky that I've been using
keychain
for a couple of decades now, so I know its process flow fairly well).When run with
wsl git ...
, WSL launches the shell (Bash) as a non-interactive, non-login shell, so~/.bashrc
is not processed. Because of this, even if the key had been previously loaded intossh-agent
(bykeychain
), the Bash session does not have the properSSH_AUTH_SOCK
andSSH_AGENT_PID
.
As a result of this, the git
commands in your plugin are likely to fail for the user, since they require key-based authentication.
I think the above at least captures the spirit of the problem you are trying to solve.
Unfortunately, there's just no method that I'm aware of to force Bash to load its startup files when it is a non-interactive, non-login shell other than things that would modify the WSL command-line.
Proposed workaround - $WSLENV
chain-loading IntelliJ
This is "pretty close" to optimal, I believe. Your users would need to launch IntelliJ through WSL and use the $WSLENV
feature to pass through the correct environment variables. This could be done interactively or through ~/.bashrc
.
Add the following to ~/.bashrc
:
eval $(keychain --eval ~/.ssh/<keyfile>)
export WSLENV=$WSLENV:SSH_AGENT_PID:SSH_AUTH_SOCK
With this in place, you should be able to run:
wsl -e bash -lic /path/to/intellij.exe
It will ask for the key password and (as normal) add the SSH_AGENT_PID
/SSH_AUTH_SOCK
environment variables to the shell session. It will also add those variable names to $WSLENV, so that they are passed to any Windows process launched from inside WSL.
When the IntelliJ Windows executable is launched this way, the three variables will also be available in its environment:
WSLENV
SSH_AGENT_PID
SSH_AUTH_SOCK
And when IntelliJ then runs wsl git ...
, those three variables will also be passed back into WSL, so that git
will be able to access the key from ssh-agent
.
While I don't have IntelliJ, I've tested this successfully using:
wsl -e bash -lic pwsh.exe # or powershell.exe
Then, from PowerShell:
> $env:WSLENV
WT_SESSION::WT_PROFILE_ID:SSH_AGENT_PID:SSH_AUTH_SOCK
> $env:SSH_AGENT_PID
45
> $env:SSH_AUTH_SOCK
/tmp/ssh-XXXXXXTWbsTa/agent.44
> cd some-dir
> wsl git clone "git@github.com:NotTheDr01ds/<private_repo>"
It worked as expected.
Other options
This is actually a bit easier if your users are using (or open to using) some shells other than Bash:
The Fish shell startup files that are sourced even for non-login, non-interactive shells plus it supports "universal variables" that allow the
SSH_A*
variables to automagically be made available to all running (and future) Fish instances.Zsh has a startup file (
~/.zshenv
) that is sourced for non-login, non-interactive shells. It's a little more complicated than Fish, but it's workable.
I actually started with these as proposed solutions before I found that $WSLENV
was a workable solution (that didn't require a shell change). However, if you want to see my write-up on how to do this in Zsh or Fish, just look at the edit history for this answer.
bashrc not loading until run bash command
Read the INVOCATION section from "bash(1)" for full details (that's the man page for bash; use man bash
). Your first shell upon logging in is a "login shell", which means that the .bashrc
file is not sourced. Your second invocation creates an interactive shell, where .bashrc
is sourced.
If you always want the content of your .bashrc
file processed, you can add the following lines to your .bash_profile
file, creating that file if it does not already exist:
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
Per its man page, bash "[...] looks for ~/.bash_profile
, ~/.bash_login
, and ~/.profile
, in that order, and reads and executes commands from the first one that exists and is readable." Conventions and policies of your local system will determine which, if any, of these files already exist.
A word of caution: be aware that creating a new .bash_profile
in your home directory could have the unintended side-effect of preventing the reading and executing of commands in a .bash_login
or .profile
file already present, changing further the behavior of subsequent logins.
Run ssh and immediately execute command
ssh -t 'command; bash -l'
will execute the command and then start up a login shell when it completes. For example:
ssh -t user@domain.example 'cd /some/path; bash -l'
Related Topics
Compiling a Linux Program for Arm Architecture - Running on a Host Os
What Does "$1/*" Mean in "For File in $1/*"
How to Get Ec2 Load Balancing Properly Set Up to Allow for Real Time File Syncing
How to Update Cudnn to a Newer Version
Need a Simple Linux C++ Ide (Android Ndk)
Merge/Join Two Tables Fast Linux Command Line
Error Running Make: Missing Separator (Did You Mean Tab Instead of 8 Spaces)
Interrupt Handling and User Space Notification
Cannot Create Backup File(Add ! to Overwrite)
Installing Mod_Ssl Amazon Linux
How to Check a File Exists and Execute a Command If Not
When Should the Option Remainafterexit Needs to Be Set True When Creating New Systemd Services
Finding Original MAC Address from Hardware Itself
How to Force Node.Js Require to Be Case Sensitive
Execution Time of an SQLite Query: Units
Making Gcc Prefer Static Libs to Shared Objects When Linking