8
votes

Does anyone know how to make environment variables registered for exec_command calls when using SSHClient?

I'm using a basic script that instantiates the SSHClient class, connects to another computer using the connect method, then sends out commands using the exec_command method. However, none of the environment variables seem to be registered when I try to issue commands. I can do basic things like 'ls' and see the stdout, but when trying to run installed programs, the fact that the environment variables are missing makes it impossible to run them. Using ssh in the command line to do the same thing works, as the environment variables for the user are set.

#!/usr/bin/python
import paramiko

ssh.connect('mymachine',username='myname',password='pass')    
stdin,stdout,stderr=ssh.exec_command('cd /myfolder/path')
stdin,stdout,stderr=ssh.exec_command('ls')

....

....

ssh.close()

Note: I can't change my directory in paramiko. I appended the cd command in the followup command in a single ssh.exec_command('cd /dddd/ddd;ls'). I have given ls as an example but my actual followup command is different.

3
Have you tried adding them via os.environ? - mgilson
I am looking to set the 'TZ' env variable as well :| How do we go about setting the 'TZ' env variable using os.environ, if it's not supported in paramiko?? Thanks. - First Blood

3 Answers

8
votes

Since release 2.1.0 2016-12-09 , you can add an environment variable dictionary to the exec_command:

import paramiko
paramiko.util.log_to_file("paramiko.log")
ssh = paramiko.SSHClient()
k =   paramiko.RSAKey.from_private_key_file("<private_key_file>")
ssh.connect(<hostname>,username=<username>,pkey=k)
env_dict={"LC_TELEPHONE":"ET_HOME","LC_MEASUREMENT":"MILES_APART"}
stdin , stdout, stderr = ssh.exec_command('echo $LC_TELEPHONE; echo "..."; echo $LC_MEASUREMENT',environment=env_dict)
print stdout.read()

output:

ET_HOME
...
MILES_APART

But why did I choose LC_TELEPHONE and LC_MEASUREMENT? Because those are two of the few environments that the target host's ssh config allows me to set:

grep AcceptEnv /etc/ssh/sshd_config 

output:

AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL

In other words, this doesn't work:

env_dict={"HELLO":"WORLD","GOODBYE":"CRUEL_WORLD"}
stdin , stdout, stderr = ssh.exec_command("echo $HELLO; echo '...'; echo $GOODBYE")
print stdout.read()

output:

...

As the documentation warns, the environment variables are silently rejected http://docs.paramiko.org/en/2.1/api/client.html http://docs.paramiko.org/en/2.1/api/channel.html#paramiko.channel.Channel.set_environment_variable

If you cannot control the target server's sshd config, putting the environment variables into a file and sourcing it works:

stdin , stdout, stderr = ssh.exec_command("cat .set_env;source .set_env; echo $HELLO; echo '...'; echo $GOODBYE")
print stdout.read()

output:

# begin .set_env
HELLO="WORLD"
GOODBYE="CRUEL_WORLD"
# end .set_env
WORLD
...
CRUEL_WORLD
1
votes
#!/usr/bin/python
import paramiko

client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy)
client.connect(myhostname, theport, myuser, thepass)
stdin,stdout,stderr = client.exec_command('cd /tmp;pwd;ls -al')
#returns your output
print stdout.read()

which all works fine for me. If you have special environment Variables you might have to set them on the remote command prompt. Maybe it helps if you write the variables into a myENV file and then call

stdin,stdout,stderr = client.exec_command('source ./myEnv')

Did you tried something like that?

1
votes

You can do: client.exec_command(..., get_pty=True).

This will make paramiko allocate a pseudo terminal, similar to ssh.