tags:

views:

134

answers:

4

I have a python script that is always called from a shell, which can be either zsh or bash.

How can I tell which one called the script?

A: 

os.system("echo $0")

This works flawlessly on my system:

cat shell.py: 

    #!/ms/dist/python/PROJ/core/2.5/bin/python

    import os
    print os.system("echo $0")


bash-2.05b$ uname -a
Linux pi929c1n10 2.4.21-32.0.1.EL.msdwhugemem #1 SMP Mon Dec 5 21:32:44 EST 2005 i686 athlon i386 GNU/Linux


pi929c1n10 /ms/user/h/hirscst 8$ ./shell.py
/bin/ksh
pi929c1n10 /ms/user/h/hirscst 9$ bash
bash-2.05b$ ./shell.py
/bin/ksh
bash-2.05b$
ennuikiller
This is incorrect, as it starts a new shell, it doesn't give any information on the "calling" shell.
static_rtti
This does not return the name of the shell, it prints it to the screen. Also at least on my system, this always prints `sh` no matter which shell I invoke python from.
sepp2k
um, this will start a subshell WITH THE SAME SHELL EXECUTABLE THAT THE SCRIPT WAS CALLED WITH!!!
ennuikiller
This works flawlessly on my system, linux redhat 5. Try this run pi929c1n10 /ms/user/h/hirscst 8$ ./shell.py/bin/kshpi929c1n10 /ms/user/h/hirscst 9$ bashbash-2.05b$ ./shell.py/bin/kshbash-2.05b$
ennuikiller
this works on my system too... I just used `echo $0`. We can assign it to any variable and use it later
Aviator
@ennuikiller: I've just tested it from both bash and zsh, and it reports "sh" for both. Unless you give more details I'm sorry but your answer is useless for me.
static_rtti
os.getenv("SHELL") reports "/bin/bash" when launched from either bash or zsh on my system.
static_rtti
A: 

You can't do this in a reliable automated way.

  • Environment variables can be misleading (a user can maliciously switch them). Most automatic shell variables aren't "leaky", i.e. they are only visible in the shell process, and not for child processes.

  • You could figure out your parent PID and then search the list of processes for that ID. Doesn't work if you're run in the background (in this case PPID is always 1).

  • A user could start your program from within a script. Which is the correct shell in this case? The one in which the script was started or the script's shell?

  • Other programs can use system calls to run your script. In this case, you'd get either their shell or nothing.

If you have absolute control over the user's environment, then put a variable in their profile (check the manuals for BASH and ZSH for a file which is always read at startup. IIRC, it's .profile for BASH).

[EDIT] Create an alias which is invoked for both shells. In the alias, use

env SHELL_HINT="x$BASH_VERSION" your_script.py

That should evaluate to "x" for zsh and to something else for bash.

Aaron Digulla
I have clearly mentioned my use case in the question. I don't give a flying fuck if the user 'maliciously' does anything, nor do I care if he starts it from withing a python script or anything else.The script is only required to work when used properly and launched from either bash or zsh.
static_rtti
Well, it won't, no matter how much you complain :) On Unix, processes are meant to be isolated. They usually don't leak stuff into child processes unless you specifically tell them so and shells are especially conservative.
Aaron Digulla
A: 
import os
shell = os.getenv('SHELL')
kwatford
This will not work if the script is not executed from the system shell.
Dana the Sane
Not particularly reliable, but simple, and is not at least wrong. :-)
Lennart Regebro
@Lennart: and doesn't work exactly when OP needs it to.
SilentGhost
+4  A: 

In Linux you can use procfs:

>>> os.readlink('/proc/%d/exe' % os.getppid())
'/bin/bash'

os.getppid() returns the PID of parent process. This is portable. But obtaining process name can't be done in portable way. You can parse ps output which is available on all unices, e.g. with psutil.

Denis Otkidach
Thanks, this is the first working answer! Plus, it's wonderfully cryptic :)
static_rtti
I would prefer a solution that works on all unices, though.
static_rtti
I've added some hints to make it more portable.
Denis Otkidach