sh startup files over ssh

I have some important commands I need to execute before any sh shell starts. This is required for passing SSH commands in the SSH command (ssh host somecommand) and other programs that run commands.

In my .profile I have this:

<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="99f0f1f8f4f4fcebf1f8f7fdead9eeebfcfaf2faebfcf8edf0f6f7ea">[email protected]</a>:~> cat .profile
#specific environment and startup programs
export PS1="<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8cf9ccfbfee9efe7effee9edf8e5e3e2ff">[email protected]</a>:w> "
export PYTHONPATH=~/python/lib/python2.4/site-packages
export PATH=$PATH:~/bin:~/python/bin

However, this fails:

W:programmingwreckcreations-sitetest-hg>ssh <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5739363a32173f382423">[email protected]</a> echo $PATH
Enter passphrase for key '/home/Owner/.ssh/id_rsa':
/usr/local/bin:/bin:/usr/bin

Notice the missing PATH options

What is the proper name for the sh profile? Note: I do not have root access and don’t want this applied to other users. Is there another way to do this?


EDIT: It appears /bin/sh links to bash, which isn’t surprising. What is surprising is that my profile is still ignored. Any suggestions?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

~/.profile is only executed by login shells. The program that calls the shell decides whether the shell will be a login shell (by putting a - as the first character of the zeroth argument on the shell invocation). It is typically not executed when you log in to execute a specific command.

OpenSSH in particular invokes a login shell only if you don’t specify a command. So if you do specify a command, ~/.profile won’t be read.

OpenSSH allows setting environment variables on the server side. This must be enabled in the server configuration, with the PermitUserEnvironment directive. The variables can be set in the file ~/.ssh/environment. Assuming you use public key authentication, you can also set per-key variables in ~/.ssh/authorized_keys: add environment="FOO=bar" at the beginning of the relevant line.

Ssh also supports sending environment variables. In OpenSSH, use the SendEnv directive in ~/.ssh/config. However the specific environment variable must be enabled with an AcceptEnv directive in the server configuration, so this may well not work out for you.

One thing that I think always works (oddly enough) as long as you’re using public key authentication is to (ab)use the command= option in the authorized_keys file. A key with a command option is good only for running the specified command; but the command in the authorized_keys file runs with the environment variable SSH_ORIGINAL_COMMAND set to the command the user specified. This variable is empty if the user didn’t specify a command and therefore expected an interactive shell. So you can use something like this in ~/.ssh/authorized_keys (of course, it won’t apply if you don’t use this key to authenticate):

command=". ~/.profile; if [ -n "$SSH_ORIGINAL_COMMAND" ]; then eval "$SSH_ORIGINAL_COMMAND"; else exec "$SHELL"; fi" ssh-rsa …

Another possibility is to write a wrapper scripts on the server. Something like the following in ~/bin/ssh-wrapper:

#!/bin/sh
. ~/.profile
exec "${0##*/}" "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="153155">[email protected]</a>"

Then make symbolic links to this script called rsync, unison, etc. Pass --rsync-path='bin/rsync' on the rsync command line, and so on for other programs. Alternatively, some commands allow you to specify a whole shell snippet to run remotely, which allows you to make the command self-contained: for example, with rsync, you can use --rsync-path='. ~/.profile; rsync'.

There is another avenue which depends on your login shell being bash or zsh. Bash always reads ~/.bashrc when it’s invoked by rshd or sshd, even if it’s not interactive (but not if it’s called as sh). Zsh always reads ~/.zshenv.

## ~/.bashrc
if [[ $- != *i* ]]; then
  # Either .bashrc was sourced explicitly, or this is an rsh/ssh session.
  . ~/.profile
fi

## ~/.zshenv
if [[ $(ps -p $PPID -o comm=) = [rs]shd && $- != *l* ]]; then
  # Not a login shell, but this is an rsh/ssh session
  . ~/.profile
fi

Method 2

It seems worth noting that the command you mention in your question

ssh <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b8d6d9d5ddf8d0d7cbcc">[email protected]</a> echo $PATH

will pretty much never be useful. The variable substitution for $PATH is done by your local shell, and passed to ssh which executes echo on the remote system to print the contents of the path variable, as it expanded on your local system. Here is an example of me doing something similar between my Mac and a Linux machine on my network:

LibMBP:~ will$ echo $PATH
/opt/local/bin:/opt/local/sbin:/Users/will/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
LibMBP:~ will$ ssh warren echo $PATH
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4a3d2326260a3d2b38382f24">[email protected]</a>'s password: 
/opt/local/bin:/opt/local/sbin:/Users/will/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
LibMBP:~ will$ ssh warren 'echo $PATH'
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c2b5abaeae82b5a3b0b0a7ac">[email protected]</a>'s password: 
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
LibMBP:~ will$

Note how I needed to use quotes to prevent my local shell from expanding the variable.

Method 3

Usually upon login, bash reads commands from:

~/.bash_profile
~/.bashrc

From bash man page:

~/.bash_profile
The personal initialization file, executed for login shells

~/.bashrc
The individual per-interactive-shell startup file

Method 4

I run out of time to test this, but looking though the man pages I found:

man bash:
When bash is started non-interactively, to run a shell script, for example, it
looks for the variable BASH_ENV in the environment, expands its value if it
appears there, and uses the expanded value as the name of a file to read and
execute. Bash behaves as if the following command were executed:
if [ -n “$BASH_ENV” ]; then . “$BASH_ENV”; fi
but the value of the PATH variable is not used to search for the file name.

man ssh:
~/.ssh/environment
Contains additional definitions for environment variables; see
ENVIRONMENT, above.

The combination suggests how you can have ssh execute your .profile

Unfortunately my server has PermitUserEnvironment to the default value of no, which makes that this does not work for me (and like I said I don’t have the time to play with it more).

Method 5

(removed… can only have one Hyperlink as new user ~)

Update

Sorry, I have not seen that this is about a non-interactive session, to which the above link does not apply.

When Bash starts in SH compatiblity
mode, it tries to mimic the startup
behaviour of historical versions of sh
as closely as possible, while
conforming to the POSIX® standard as
well. The profile files read are
/etc/profile and ~/.profile, if it’s a
login shell.

If it’s not a login shell, the
environment variable ENV is evaluated
and the resulting filename is taken as
name of the startup file.

After the startup files are read, Bash
enters the POSIX(r) compatiblity mode
(for running, not for starting!).

Bash starts in sh compatiblity mode
when:

  • the base filename in argv[0] is sh (:!: Attention dear uber-clever
    Linux users… /bin/sh may be linked
    to /bin/bash, but that doesn’t mean it
    acts like /bin/bash :!:)

So the question is, why doesn’t it execute it, even though your shell is started like this.

Source


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x