OSError: [Errno 2] Brak takiego pliku lub katalogu podczas korzystania z podprocesu Python w Django

137

Próbuję uruchomić program, aby wykonać kilka wywołań systemowych w kodzie Pythona, przy użyciu subprocess.call()którego zgłasza następujący błąd:

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

Mój rzeczywisty kod w Pythonie wygląda następująco:

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)

Czy mogę uzyskać przydatne porady, jak rozwiązać ten problem?

Sandeep Mederametla
źródło
Pytanie, które zostało powtórzone w tym pytaniu, ma znacznie lepszą odpowiedź. Należy ponownie otworzyć to pytanie, a zamiast tego powielić je.
user3553031

Odpowiedzi:

301

Użyj, shell=Truejeśli przekazujesz ciąg do subprocess.call.

Z dokumentów :

Jeśli przekazywany jest pojedynczy łańcuch, shellmusi albo być, Truealbo łańcuch musi po prostu nazwać program, który ma zostać wykonany, bez podawania żadnych argumentów.

subprocess.call(crop, shell=True)

lub:

import shlex
subprocess.call(shlex.split(crop))
Ashwini Chaudhary
źródło
7
Python 3 podaje lepszy komunikat o błędzie, nazywając nieprawidłowy „plik”, ale nie daje żadnej wskazówki, że powłoka = True jest wymagana. Dziękuję Ci!
AnneTheAgile
14
Należy pamiętać, że dokumentacja stwierdza również, że „użycie polecenia shell=Truejest zdecydowanie odradzane w przypadkach, gdy ciąg poleceń jest tworzony na podstawie danych wejściowych z zewnątrz”, patrz link w odpowiedzi.
ważny
23
@AnneTheAgile: shell=Truenie jest wymagane. Ponadto nie powinieneś go używać, chyba że jest to konieczne (patrz komentarz @ valid). Powinieneś zamiast tego przekazać każdy argument wiersza poleceń jako oddzielny element listy, np. Użyj ['command', 'arg 1', 'arg 2']zamiast "command 'arg 1' 'arg 2'".
jfs
3
@ user3553031 Nie polecam go w stosunku do innych formatów. Po prostu zwróciłem uwagę na fakt, że jeśli używasz łańcucha, będziesz musiał go użyć shell=True. Aspekty bezpieczeństwa wykraczają poza zakres tego pytania.
Ashwini Chaudhary
6
@ user3553031 Nie zawsze jest to odradzane, dokumentacja wyraźnie mówi, że nie jest to bezpieczne, gdy dane wejściowe pochodzą z wejścia zewnętrznego . Mówienie, że nigdy nie powinieneś go używać, jest nonsensem. A pytań o podproces jest tak wiele, że nie ma sensu wspominać o tym w każdej odpowiedzi. Są już komentarze na ten temat od innych użytkowników, a ja również udostępniłem link do dokumentacji. Zapraszam do edycji mojej odpowiedzi.
Ashwini Chaudhary
5

Nie mogę zagłosować, więc opublikuję komentarz @jfs, ponieważ myślę, że powinien być bardziej widoczny.

@AnneTheAgile: shell = True nie jest wymagane. Ponadto nie powinieneś go używać, chyba że jest to konieczne (patrz komentarz @ valid). Powinieneś zamiast tego przekazać każdy argument wiersza poleceń jako oddzielny element listy, np. Użyj ['command', 'arg 1', 'arg 2'] zamiast "command 'arg 1' 'arg 2'". - jfs 3 marca 2015 o 10:02

Dusan Maksic
źródło
2

No such file or directorymożna również podnieść, jeśli próbujesz wstawić argument plikowy za Popenpomocą podwójnych cudzysłowów.

Na przykład:

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

W takim przypadku musisz usunąć podwójne cudzysłowy.

call_args = ['mv', 'path/to/file with spaces.txt', 'somewhere']
Daniil Mashkin
źródło