Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using os.execlp, why `python` needs `python` as argv[0]

The code is like this:

os.execlp('python', 'python', 'child.py', #other args#)  # this works

os.execlp('python', 'child.py', #other args#)  # this doesn't work

I read this question: execlp() in python

But I'm still confused. The answer said:

The first argument is the program to execute (found on the PATH). The rest are the sys.argv arguments to the program.

However, if I run: python child.py 1 2 3 and the sys.argv of this process would be ["child.py", "1", "2", "3"], where the python doesn't exist. Then why should I add python as the second parameter of os.execlp?

like image 716
Hanfei Sun Avatar asked Jan 05 '13 17:01

Hanfei Sun


3 Answers

When python is executed, it creates sys.argv for you. The values in that list are based on the arguments passed to it by the operating system, but it leaves off the sys.executable value from that list.

In other words, when Python is invoked, it sets sys.argv to everything but it's own executable.

When you invoke a new executable via os.execlp(), you still need to include Python in that as that is what executable that the OS will run. The first two values of what you a pass to os.execlp() are still required, whatever you find in sys.argv later on.

like image 130
Martijn Pieters Avatar answered Oct 21 '22 21:10

Martijn Pieters


The second python is a name for python, it can be any string, but it has to be there.

See the second paragraph of http://docs.python.org/3/library/os.html?highlight=os.exec#process-management:

The various exec* functions take a list of arguments for the new program loaded into the process. In each case, the first of these arguments is passed to the new program as its own name rather than as an argument a user may have typed on a command line. For the C programmer, this is the argv[0] passed to a program’s main(). For example, os.execv('/bin/echo', ['foo', 'bar']) will only print bar on standard output; foo will seem to be ignored.

like image 38
hgajshb Avatar answered Oct 21 '22 21:10

hgajshb


I realize this was answered LONG ago and the answer is basically right, but there are a few things that are misleading in the way it is worded and in the comments to the answer that I would like to address.

First, I think the clearer way to state what is happening is to highlight that the difference is between the Unix argv list that a process gets handed by the OS and the python sys.argv. The python sys.argv is the Unix argv list with the first element (the command name) removed.

The various os.exec* commands use their first argument to be the actual executable to invoke and the remainder of the line is the Unix argv list, which means that the second argument passed to execlp will be interpreted by the executable as the command line name it was invoked as.

Which takes us to the problem with the comment. The reason that the ls example os.execlp('ls','.') "works" is not because ls does anything special to detect it is called with too few arguments. This example code starts the 'ls' executable with the unix argv list being ['.']. That just means that the ls executable gets started while being told (oddly) that it was invoked as '.', and there are no other command line arguments. And what does ls do when it is run with no other command line arguments: it prints the contents of the current directory, or exactly what one mistakenly thought they were doing when the invoked os.execlp('ls', '.').

You can see that this example really isn't "working" by instead trying os.execlp('ls', '/some/non-existant/path'). That also prints out the contents of the current working directory, and would not be mistaken for "working".

like image 1
Malcolm Avatar answered Oct 21 '22 22:10

Malcolm