20

I execute a command in python using subprocess.popen() function like the following:

omp_cmd = 'cat %s | omp -h %s -u %s -w %s -p %s -X -' %(temp_xml, self.host_IP, self.username, self.password, self.port)
xmlResult = Popen(omp_cmd, stdout=PIPE, stderr=STDOUT)

In the shell it runs fine without error, but in Python I get:

  File "/home/project/vrm/apps/audit/models.py", line 148, in sendOMP
    xmlResult = Popen(omp_cmd, stdout=PIPE, stderr=STDOUT)
  File "/usr/local/lib/python2.7/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/local/lib/python2.7/subprocess.py", line 1228, in _execute_child
    raise child_exception
  OSError: [Errno 2] No such file or directory

I searched the error but none of them solved my problem. Does anyone know what's the cause of this issue?

Paolo
  • 20,112
  • 21
  • 72
  • 113
Shang Wang
  • 24,909
  • 20
  • 73
  • 94

2 Answers2

26

If you're going to pass the command as a string to Popen and if the commands have pipes to other commands in there, you need to use the shell=True keyword.

I'm not particularly familiar with the omp command, but this smells an awful lot like a useless use of cat. I would think that a better way to achieve this would be to:

import shlex
omp_cmd = 'omp -h %s -u %s -w %s -p %s -X %s' \
%(self.host_IP, self.username, self.password, self.port, temp_xml)
xmlResult = Popen(shlex.split(omp_cmd), stdout=PIPE, stderr=STDOUT)

Or, if it's not a useless use of cat (You really do need to pipe the file in via stdin), you can do that with subprocess too:

import shlex
omp_cmd = 'omp -h %s -u %s -w %s -p %s -X -' \
%(self.host_IP, self.username, self.password)
with open(temp_xml) as stdin:
    xmlResult = Popen(shlex.split(omp_cmd), stdin=stdin, 
    stdout=PIPE, stderr=STDOUT)
SL5net
  • 2,282
  • 4
  • 28
  • 44
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • You are right!! One more question, if shell=False, should the args be a list, right? What's the difference between these two ways? – Shang Wang Jul 19 '12 at 18:26
  • 1
    To answer your question, that command that I stores in the file is 9000 lines long, my OS will give me "arg list too long error" :) – Shang Wang Jul 19 '12 at 18:28
  • 2
    @da_zhuang -- yes, with `shell=False`, the args are typically a list. I used the `shlex.split` function which takes a string and splits it up into a list the same way a typical shell would. with `shell=True`, you pass a string and that string is evaluated by a shell. with `shell=False` you pass a string or a list. If a string, it is evaluated as if it was the only command. (`"ls -l"` would fail since there is no command `ls -l`, only `ls`). If it's a list, each element is taken as a argument. `["ls", "-l"]` – mgilson Jul 19 '12 at 18:29
  • @da_zhuang -- I've edited with a version with preserves the original reading from stdin, but still removes the dependence on `cat` and hence the need to use `shell=True`. The problem with `shell=True` is that it is vulnerable to shell injection if given untrusted input. (say `self.host_IP` somehow was assigned the value `"; rm -rf ~;"`) – mgilson Jul 19 '12 at 18:38
0

This error has also occured for me too with tox scripts, turns out that a virtualenv is created with tox which has an asolute path with length about 96 characters but whenever it takes your absolute 'bin/pip' path to near about 123 chars, there is an invocation error, OSError2.

'ERROR: invocation failed (errno 2), OSError: [Errno 2] No such file or directory'

Python: Python 2.7.6 virtualenv:15.1.0 tox: 2.9.1 pip: 9.0.1 ubuntu 14.04 test ran with coverage: django(1.8-1.11) tests with py27, py35 each

Resolution: I created my virtualenv(with abs path <=(96-100) chars) first where tox is installed, cloned my project to be used with this tox installation and virtualenv, tox creates it own virtualenvs now and it runs fine.

hope it helps.

gaurav arora
  • 195
  • 3
  • 11