1

An often asked question, I know, but after searching through other solutions I'm still having problems. Most solutions say to make sure your variables are exported before trying to access them, but have done that in my .profile

pi@raspberrypi ~ $ cat .profile | grep "export"
export MYCODE=/home/pi/Code
export MYINSTALL=/home/pi/gs_dist

After running the .profile again, the variables are clearly visible.

pi@raspberrypi ~ $ . .profile
pi@raspberrypi ~ $ env | grep "MY"
MYCODE=/home/pi/Code
MYINSTALL=/home/pi/gs_dist

And the variables are being properly exported and are visible to sub shells

pi@raspberrypi ~ $ echo $MYCODE
/home/pi/Code
pi@raspberrypi ~ $ bash
pi@raspberrypi ~ $ echo $MYCODE
/home/pi/Code
pi@raspberrypi ~ $ exit
pi@raspberrypi ~ $

I'm running my application via a custom script /usr/bin/mycmd which throws an error caused by os.getenv() not finding MYCODE.

pi@raspberrypi ~ $ mycmd start
unsupported operand type(s) for +: 'NoneType' and 'str'

Here are the relevant parts of my code

/usr/bin/mycmd

#!/bin/bash
case "$1" in
  start)
     sudo python $MYCODE/launcher.py
    ;;

/home/pi/Code/launcher.py

import os
import subprocess
import time
import datetime

processlist = []

def main():
        p = subprocess.Popen(['python', os.getenv('MYCODE') + '/sensor_launcher.py'])
        p2 = subprocess.Popen(['python', os.getenv('MYCODE') + '/server_listener.py'])
        processlist.append(p)
        processlist.append(p2)

        while True:
                #just loop until program is exited...
                pass

if __name__ == "__main__":
        try:
                main()
        except Exception as e:
            print str(e)
            pass
        finally:
                print "killing processes..."
                processlist[0].terminate()
                processlist[1].terminate()

So for some reason, the python script is not able to see the environment variable even though it is exported.

Now here's where it gets really interesting. If I open up a python shell and try to access the variable...

pi@raspberrypi ~ $ python
Python 2.7.13 (default, Nov 24 2017, 17:33:09) 
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> print os.getenv("MYCODE")
/home/pi/Code
>>> 

it works!

Also of note, I add the lines

print os.getenv('PATH')
print os.getenv('MYCODE')

into main(), it says

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
None

BUT, that's not what my PATH actually is.

pi@raspberrypi ~ $ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

So clearly, something very strange is going on. Why is this happening? How can I fix this so that the python script gets the correct values?

  • 2
    Do you need to use sudo? It is dangerous and bad practice unless needed. – joan Jun 20 '18 at 15:28
6

The problem is the use of sudo. sudo will clear environment variables by default.

You can use sudo -E (or --preserve-env) to not clear the environment. This can also be set in your sudoers file.

  • Bravo! I've learned something today :) – Seamus Jun 20 '18 at 19:07
0

python script

#!/usr/bin/python3
#
# argstest.py

import sys

for line in sys.stdin.readlines():
    print('boom', line)

from bash

export -p | ./argstest.py

from the man page

The export special built-in shall support the Base Definitions volume of POSIX.1-2008, Section 12.2, Utility Syntax Guidelines.

       When -p is specified, export shall write to the standard output the names and values of all exported variables, in  the  following
       format:

           "export %s=%s\n", <name>, <value>

if you really wanted to get wacky . . .

export -p | ./argstest.py | export

and from python

sys.stdout.write(whateva)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.