188

I am trying to run a program to make some system calls inside Python code using subprocess.call() which throws the following error:

Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.7/subprocess.py", line 493, in call
      return Popen(*popenargs, **kwargs).wait()
      File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
      File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
      raise child_exception
      OSError: [Errno 2] No such file or directory

My actual Python code is as follows:

url = "/media/videos/3cf02324-43e5-4996-bbdf-6377df448ae4.mp4"
real_path = "/home/chanceapp/webapps/chanceapp/chanceapp"+url
fake_crop_path = "/home/chanceapp/webapps/chanceapp/chanceapp/fake1"+url
fake_rotate_path = "/home/chanceapp/webapps/chanceapp.chanceapp/fake2"+url
crop = "ffmpeg -i %s -vf "%(real_path)+"crop=400:400:0:0 "+ "-strict -2 %s"%(fake_crop_path)
rotate = "ffmpeg -i %s -vf "%(fake_crop_path)+"transpose=1 "+"%s"%(fake_rotate_path)
move_rotated = "mv"+" %s"%(fake_rotate_path)+" %s"%(real_path)
delete_cropped = "rm "+"%s"%(fake_crop_path)
#system calls:
subprocess.call(crop)

Can I get some relevant advice on how to solve this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Sandeep Mederametla
  • 1,891
  • 2
  • 12
  • 5
  • [The question that was duplicated to this question](https://stackoverflow.com/questions/33653525/python-subprocess-call-with-variables) has a much better answer. That question should be re-opened and this one duplicated to it instead. – user3553031 Oct 30 '17 at 20:31
  • Does this answer your question? [Python subprocess.Popen() error (No such file or directory)](https://stackoverflow.com/questions/30010939/python-subprocess-popen-error-no-such-file-or-directory) – mkrieger1 Jul 20 '22 at 12:08

3 Answers3

401

Use shell=True if you're passing a string to subprocess.call.

From docs:

If passing a single string, either shell must be True or else the string must simply name the program to be executed without specifying any arguments.

subprocess.call(crop, shell=True)

or:

import shlex
subprocess.call(shlex.split(crop))
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 8
    Python 3 gives a better error message, naming the offending 'file', but it gives no hint that shell=True is required. Thank you! – AnneTheAgile Nov 08 '14 at 00:04
  • 18
    Be aware, the docs also state "the use of `shell=True` is **strongly discouraged** in cases where the command string is constructed from external input", see link in the answer. – valid Nov 12 '14 at 04:01
  • 37
    @AnneTheAgile: `shell=True` is not required. Moreover you should not use it unless it is necessary (see @ valid's comment). You should pass each command-line argument as a separate list item instead e.g., use `['command', 'arg 1', 'arg 2']` instead of `"command 'arg 1' 'arg 2'"`. – jfs Mar 03 '15 at 10:02
  • 1
    don't use `shlex.split()` blindly. It has some edge cases such as `shlex.split(r'echo "\$"')`. Construct the list directly instead `['echo', '$']`. – jfs Mar 03 '15 at 10:08
  • 1
    @J.F.Sebastian can we consider that as a shlex bug? – Ashwini Chaudhary Mar 03 '15 at 10:21
  • 1
    it is documented as [*"using shell-like syntax"*](https://docs.python.org/3/library/shlex.html). It neither promises to understand a real shell syntax nor it should (the syntax is too complicated for a human). – jfs Mar 03 '15 at 10:37
  • Down-voting due to the unsafe recommendation to use shell=True. Build an argument list as jfs suggests instead. – user3553031 Oct 30 '17 at 20:02
  • 3
    @user3553031 I am not recommending it over other formats. I have simply pointed out the fact if you're using a string then you will have to use `shell=True`. The security aspects are beyond the scope of this question. – Ashwini Chaudhary Oct 31 '17 at 05:09
  • @AshwiniChaudhary You could equally have said that one should pass an argument list rather than a string if one wishes to provide arguments to the command being invoked. Sure, passing a string that contains arguments requires `shell=True`, but that's also **explicitly discouraged** by the documentation, so its a bad answer. – user3553031 Oct 31 '17 at 16:54
  • 8
    @user3553031 It's not always discouraged, the documentation clearly says it is not safe when the input is **coming from an external input**. Saying you should not use it ever is nonsense. And there are so many questions about subprocess, it doesn't make any sense to mention this in every answer. There are already comments about it from other users and I have shared the link to documentation as well. You're welcome to edit my answer. – Ashwini Chaudhary Oct 31 '17 at 18:43
  • 1
    adding shell=True to subprocess.call() worked for me ...thank you so much – RCP Nov 24 '17 at 07:05
  • @AshwiniChaudhary I think it is good to just point out that using `shell=True` has some security concerns. Concerned people can then further read about it. – Nagabhushan S N Apr 20 '20 at 17:54
  • I am not great in this area but I was running ssh-add ~/.ssh/ito and I was not able to do that without shell=True parameter. – kta Aug 15 '23 at 09:39
13

No such file or directory can be also raised if you are trying to put a file argument to Popen with double-quotes.

For example:

call_args = ['mv', '"path/to/file with spaces.txt"', 'somewhere']

In this case, you need to remove double-quotes.

call_args = ['mv', 'path/to/file with spaces.txt', 'somewhere']
Danil
  • 4,781
  • 1
  • 35
  • 50
9

Can't upvote so I'll repost @jfs comment cause I think it should be more visible.

@AnneTheAgile: shell=True is not required. Moreover you should not use it unless it is necessary (see @ valid's comment). You should pass each command-line argument as a separate list item instead e.g., use ['command', 'arg 1', 'arg 2'] instead of "command 'arg 1' 'arg 2'". – jfs Mar 3 '15 at 10:02

Dusan Maksic
  • 99
  • 1
  • 3