4

I'm trying to retrieve environment variables of a remote Linux server in Python. Alternatively, if I could use the variable name in the command I'm executing, that'd be great as well. The calls I'm making should work, as far as I can tell, but I'm getting back garbage. I have set up public-key authentication, so no password required.

Effort 1:

devdir = subprocess.check_output(["ssh", connectstring, "echo $DEVDIR"])

Effort 2:

ret = subprocess.check_output(["ssh", connectstring, 
    "$DEVDIR/{0}".format(testpath)])

connectstring is user@ip and works fine. $DEVDIR is the remote variable I want to use and contains a path. testpath is the path to the script I'm trying to execute, rooted at $DEVDIR.

Effort 1 returns "\n", Effort 2 fails to resolve $DEVDIR remotely.


Effort 3:

import paramiko
...
ssh = paramiko.SSHClient()
ssh.connect(ip, user)    # succeeds
stdin, stdout, stderr = ssh.exec_command("echo $DEVDIR")

result: stdout.readlines() = "\n"

TravisThomas
  • 611
  • 1
  • 8
  • 21
  • are you sure that `$DEVDIR` is set appropriately? If it works if you log in manually, but fails at remote command execution, I suspect it to be set at login sessions only... – glglgl Apr 24 '13 at 16:42
  • @glglgl, that may be it--$DEVDIR is set by .bashrc. I'll try exporting the variable in .profile. – TravisThomas Apr 24 '13 at 16:46
  • I tried exporting in .profile with no luck. I also tried executing `ssh.exec_command("source ~/.bashrc")` followed by the `ssh.exec_command("echo $DEVDIR")` command and got the same `\n` result. – TravisThomas Apr 24 '13 at 16:51
  • I think you might have to remotely execute `sh -c "echo $DEVDIR"` because it's the shell which sets it, although it might make more sense just to remotely execute `cat .bashrc`, and pull it from there directly. – Aya Apr 24 '13 at 16:51
  • as just written in my answer: what does `ssh.exec_command("env")` give? (Not the full output, please; just the relevant part.) – glglgl Apr 24 '13 at 16:53

3 Answers3

3

If the environment variable is set in .bashrc, you can force the remote command to run under a login shell with the -l option. The following...

devdir = subprocess.check_output(["ssh", connectstring, "sh -l -c 'echo $DEVDIR'"])

...works for me.

Aya
  • 39,884
  • 6
  • 55
  • 55
1

Executing a command va SSH does not produce a login session. So some variables might not be set.

You can check this by replacing the variable with another one such as $HOSTNAME or $HOST or $SSH_CONNECTION or by executing the env command.

A solution might be to put the variable assignment into a file which is executed in a non-login session as well. .bashrc should be fine, however; maybe there is a flaw somewhere inside.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • You are right: `ssh.exec_command("env")` shows a much shorter list of environment variables that demonstrate that .bashrc isn't being loaded. – TravisThomas Apr 24 '13 at 16:56
  • I don't think this will work. From the `ssh` manpage, "If command is specified, it is executed on the remote host instead of a login shell", which sounds like you don't even get a shell. – Aya Apr 24 '13 at 17:14
  • @Aya The "instead" refers to the "login" part of "login shell". You get a shell, which gets the complete command line transferred over the line. Try `ssh localhost ps $$` and see how `$$` is translated into the real process ID. So that works definitely via a shell on the contacted host. – glglgl Apr 24 '13 at 17:24
  • `ssh localhost ps $$` will show the process info for the shell which is executing `ssh`, because `$$` is substituted by the shell before it executes the command. If you just ask `ps` to show processes associated with the current session, with `ssh localhost ps`, you'll see the the remote 'shell' is actually just `ps`. – Aya Apr 24 '13 at 17:31
-1

Try this:

devdir = subprocess.check_output(["ssh -i", connectstring, "echo $DEVDIR", FALSE])

It's a bit of a hack, but it should help.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • Doesn't work. Adding `-i` gives error `OSError: [Errno 2] No such file or directory`, and adding `False` (not `FALSE`) gives error `TypeError: execv() arg 2 must contain only strings` – TravisThomas Apr 24 '13 at 16:23
  • If adding argument `-i`, it should be done as a separate argument and not added to the command name. And then `-i` is missing the identity file name. And what `FALSE` resp. `False` should be good for in this context is beyond my understanding. – glglgl Apr 24 '13 at 16:33