sh startup files over ssh

15,630

Solution 1

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

ssh name@host 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
will@warren'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'
will@warren'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.

Solution 2

~/.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##*/}" "$@"

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

Solution 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

Share:
15,630

Related videos on Youtube

TheLQ
Author by

TheLQ

Updated on September 17, 2022

Comments

  • TheLQ
    TheLQ over 1 year

    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:

    ihammerhands@wreckcreations:~> cat .profile
    #specific environment and startup programs
    export PS1="\u@wreckcreations:\w> "
    export PYTHONPATH=~/python/lib/python2.4/site-packages
    export PATH=$PATH:~/bin:~/python/bin
    

    However, this fails:

    W:\programming\wreckcreations-site\test-hg>ssh name@host 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?

    • Admin
      Admin over 13 years
      I don't feel like repeating what's in the man page, so just look in the bash man page under the section 'INVOCATION'. It's near the top and describes all you need to know.
    • Admin
      Admin over 13 years
      You could try using ssh name@host -t echo $PATH.
    • Admin
      Admin over 13 years
      @Gert Output is the same
    • Admin
      Admin over 13 years
      @camh Do you think I would ask this question if I didn't already check the man pages? I've read them many times + other posts but never could find an answer to this specific issue, since I'm not sure which stage ssh commands and other program's commands are executed in
    • Admin
      Admin over 13 years
      Don't set PS1 from .profile, set it in .bashrc instead, and don't export it. See Difference between .bashrc and .bash_profile, Which setup files should be used for setting up environment variables with bash?.
    • Admin
      Admin over 13 years
      @Giles All of the bash profiles fail when the command is executed by another program.
    • Admin
      Admin over 13 years
      @TheLQ: I don't know you so I don't know if you would check the man page. All I knew is that the answers were right there, so instead of repeating it word for word, I pointed you at it. A more specific pointer is to look up non-interactive shells since that's what your ssh scenario is. If something in the man page is not clear, perhaps you can ask a more specific question.
  • TheLQ
    TheLQ over 13 years
    In Windows Cygwin land, single quotes do nothing in Cygwin or Command prompt. Strangely, double quotes make the PATH expand completely to my local machine in Cygwin. So whatever ssh was giving me wasn't my path, it was the server's
  • Admin
    Admin over 13 years
    I've looked but as I told camh I do not know which stage ssh commands and other program commands are executed in. I've read the man pages and other guides many times already
  • TheLQ
    TheLQ over 13 years
    Even if I could get SSH to work by explicitly stating some environment variables in the environment, it still won't help fix making my profile be executed when other programs call commands
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 13 years
    @TheLQ The single quotes are necessary at a unix prompt (including Cygwin), but you don't need any quotes at a cmd prompt.
  • TheLQ
    TheLQ over 13 years
    What about commands that other commands execute? In this case it would be Mercurial hooks. Mercurial needs to be on the path for the hook to even think of working
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 13 years
    Use any of the techniques I indicated to have your profile run in noninteractive ssh commands. One of them (command= in authorized_keys) works transparently. Others require a specific shell or options in the ssh server configuration. The Mercurial equivalent of --rsync-path is --remotecmd.
  • mforbes
    mforbes about 11 years
    It might be useful to some to include the same full command= command as in your post superuser.com/a/207262/137762
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 2 years
    @zevzek Sure, but typically if users have a restricted shell you wouldn't allow them to edit files in ~/.ssh, so they wouldn't be able to take advantage of PermitUserEnvironment. On the other hand, AcceptEnv * is definitely bad if you have any kind of restricted shell or forced command.