File not found error when launching a subprocess containing piped commands
You have to add shell=True
to execute a shell command. check_output
is trying to find an executable called: date | grep -o -w '"+tz+"'' | wc -w
and he cannot find it. (no idea why you removed the essential information from the error message).
See the difference between:
>>> subprocess.check_output('date | grep 1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/subprocess.py", line 603, in check_output
with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
File "/usr/lib/python3.4/subprocess.py", line 848, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.4/subprocess.py", line 1446, in _execute_child
raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'date | grep 1'
And:
>>> subprocess.check_output('date | grep 1', shell=True)
b'gio 19 giu 2014, 14.15.35, CEST\n'
Read the documentation about the Frequently Used Arguments for more information about the shell
argument and how it changes the interpretation of the other arguments.
Note that you should try to avoid using shell=True
since spawning a shell can be a security hazard (even if you do not execute untrusted input attacks like Shellshock can still be performed!).
The documentation for the subprocess module has a little section about replacing the shell pipeline.
You can do so by spawning the two processes in python and use subprocess.PIPE
:
date_proc = subprocess.Popen(['date'], stdout=subprocess.PIPE)
grep_proc = subprocess.check_output(['grep', '1'], stdin=date_proc.stdout, stdout=subprocess.PIPE)
date_proc.stdout.close()
output = grep_proc.communicate()[0]
You can write some simple wrapper function to easily define pipelines:
import subprocess
from shlex import split
from collections import namedtuple
from functools import reduce
proc_output = namedtuple('proc_output', 'stdout stderr')
def pipeline(starter_command, *commands):
if not commands:
try:
starter_command, *commands = starter_command.split('|')
except AttributeError:
pass
starter_command = _parse(starter_command)
starter = subprocess.Popen(starter_command, stdout=subprocess.PIPE)
last_proc = reduce(_create_pipe, map(_parse, commands), starter)
return proc_output(*last_proc.communicate())
def _create_pipe(previous, command):
proc = subprocess.Popen(command, stdin=previous.stdout, stdout=subprocess.PIPE)
previous.stdout.close()
return proc
def _parse(cmd):
try:
return split(cmd)
except Exception:
return cmd
With this in place you can write pipeline('date | grep 1')
or pipeline('date', 'grep 1')
or pipeline(['date'], ['grep', '1'])
FileNotFound error when executing subprocess.run()
Like Jean-François Fabre said, the solution is to add "shell=True" to the call
import subprocess
result = subprocess.run("echo \"blah\"", cwd=directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
shell=True
seems to tell subprocess to use the string as a command.
subprocess: FileNotFound
FileNotFoundError: [Errno 2] No such file or directory: 'command'
command
is a shell builtin. subprocess.Popen
does NOT run the shell by default.
To run the shell, pass shell=True
:
>>> import subprocess
>>> subprocess.check_output('command -v python', shell=True)
b'/usr/bin/python\n'
To find the full path to an executable, you could use shutil.which()
instead:
>>> import shutil
>>> shutil.which('python')
'/usr/bin/python'
Subprocess command shows FileNotFoundError: [Errno 2] No such file or directory
Your commands are still wrong. If you just want to run these commands like the shell does, the absolutely easiest way to do that is to ... use the shell.
result = subprocess.run('''
# useless cat, but bear with
cat output3.txt |
sed 's/"/ /g' |
grep "shipOption" |
grep -v "getShipMethod" |
cut -d ',' -f2 |
sed 's/"//g' |
sort |
uniq -c |
sort -nr |
head -10
''',
# Probably add these too
check=True,
capture_output=True,
# We are using the shell for piping etc
shell=True)
If you want to remove the shell=True
and manually run all these processes, you have to understand how the shell works. In particular, you need to fix the quoting so that the commands you run have the quotes which remain after the shell has processed the syntactic quotes.
p1 = subprocess.Popen(['cat', 'output3.txt'], stdout=subprocess.PIPE) # still useless
p2 = subprocess.Popen(['sed','s/"/ /g'], stdin=p1.stdout, stdout=subprocess.PIPE)
p3 = subprocess.Popen(['grep', "shipOption"], stdin=p2.stdout,stdout=subprocess.PIPE)
p4 = subprocess.Popen(['grep', '-v', "getShipMethod"], stdin=p3.stdout, stdout=subprocess.PIPE)
p5 = subprocess.Popen(['cut', '-d', ',', '-f2'], stdin=p4.stdout, stdout=subprocess.PIPE)
p6 = subprocess.Popen(['sed', 's/"//g'],stdin=p5.stdout, stdout=subprocess.PIPE)
p7 = subprocess.Popen(['sort'], stdin=p6.stdout, stdout=subprocess.PIPE)
p8 = subprocess.Popen(['uniq', '-c'], stdin=p7.stdout, stdout=subprocess.PIPE)
p9 = subprocess.Popen(['sort', '-nr'], stdin=p8.stdout, stdout=subprocess.PIPE)
p0 = subprocess.Popen(['head', '-10'], stdin=p9.stdout, stdout=subprocess.PIPE)
Notice in particular how the arguments to sed
and grep
have their outer quotes removed, and how we removed shell=True
everywhere. As a rule of thumb, if the first argument to Popen
(or other subprocess
methods) is a list, you should not use shell=True
, and vice versa. (There are situations where you can pass a list to shell=True
but ... let's not even begin to go there.)
All of this seems rather moot, though, since Python can eminently well do all of these things.
from collections import Counter
counts = Counter()
with open('output3.txt', 'r', encoding='utf-8') as lines:
for line in lines:
line = line.rstrip('\n').replace('"', ' ')
if "shipOption" in line and "getShipMethod" not in line:
field = line.split(',')[1].replace('"', '')
counts[field] += 1
print(counts.most_common(10))
Probably you would want to put the rstrip
and replace
inside the if
to avoid unnecessary work. The same refactoring could be done to the shell pipeline, of course.
FileNotFoundError: subprocess.Popen(['dir'] (Windows 7)
As dir
is simply a command understood by cmd.exe
(or powershell.exe
) then you could:
subprocess.Popen(["cmd", "/c", "dir", "c:\\Users"], stdout=subprocess.PIPE)
which corresponds to doing the following in a shell
C:\>cmd /c dir c:\Users
You may find you have to fully path cmd
, as c:\\Windows\\System32\\cmd.exe
FileNotFoundError from subprocess.run when executing command from /usr/bin/* - Python
After troubleshooting I found that problem was not related to Python or its subprocess module, but actually it was due to Firefox being installed as snap package in Ubuntu. I don't know much about snap packages but they provide confined environment for installed application.
So, native app (Python script) is launched by extension or Firefox snap in that confined environment and it is unable to find system programs. Also, the Python traceback mention of Python3.5 was due to because script was interpreted by snap packaged version of Python in /snap/core/current/usr/bin/python3
instead of system global Python. I guess equivalent directory for snap packages are snap/core/current/bin/
and /snap/core/current/usr/bin/
. Also, you're not allowed to modify snap directories, so dig
can't be copied over.
There may exist alternate solution(s) but I decided to remove Firefox snap and reinstall Firefox as regular program from official Mozilla website. Now, everything works fine as expected.
Related Topics
Imports in _Init_.Py and 'Import As' Statement
What Is the Correct Way to Set Python's Locale on Windows
How to Check Blas/Lapack Linkage in Numpy and Scipy
Parsing a JSON String Which Was Loaded from a CSV Using Pandas
Comparing Python Dictionaries and Nested Dictionaries
How to Use Inspect to Get the Caller's Info from Callee in Python
How to Set Default Python Version to Python3 in Ubuntu
Zlib.Error: Error -3 While Decompressing: Incorrect Header Check
How to Set the Absolute Position of Figure Windows with Matplotlib
Django Submit Two Different Forms with One Submit Button
Why Do "Not a Number" Values Equal True When Cast as Boolean in Python/Numpy
Product Code Looks Like Abcd2343, How to Split by Letters and Numbers
Make a Post Request While Redirecting in Flask
Python Read from Subprocess Stdout and Stderr Separately While Preserving Order
Django Return Redirect() with Parameters
How to Get Last Items of a List in Python
Remove Namespace and Prefix from Xml in Python Using Lxml
Python Attributeerror: 'Module' Object Has No Attribute 'Serial'