I want to use subprocess.check_output() with ps -A | grep 'process_name'.
I tried various solutions but so far nothing worked. Can someone guide me how to do it?
9 Answers
To use a pipe with the subprocess module, you can pass shell=True but be aware of the Security Considerations. It is discouraged using shell=True. In most cases there are better solutions for the same problem.
However, this isn't really advisable for various reasons, not least of which is security. Instead, create the ps and grep processes separately, and pipe the output from one into the other, like so:
ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()
In your particular case, however, the simple solution is to call subprocess.check_output(('ps', '-A')) and then str.find on the output.
16 Comments
shell=Truesubprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1 just means that nothing was found by grep, so it's normal behaviour.ps.wait() for when we already have the output. ps.wait.__doc__ waits for the child to terminate but the content of the child seems already placed into the output variablestring.find, which has been deprecated in favor of str.find (i.e., the method find on str objects).grep dies prematurely; ps may hang indefinitely if it produces enough output to fill its OS pipe buffer (because you haven't called ps.stdout.close() in the parent). Swap the starting order, to avoid itOr you can always use the communicate method on the subprocess objects.
cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
The communicate method returns a tuple of the standard output and the standard error.
7 Comments
communicate is better than wait. There is such warning: "This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that."subprocess.check_output, not too poorly but unattractively. As the documentation suggests, you should avoid the low-level Popen when the library already provides higher-level functions which take care of all this plumbing in a single line of code, often with better behavior for boundary conditions.Using input from subprocess.run you can pass the output of one command into a second one.
import subprocess
ps = subprocess.run(['ps', '-A'], check=True, capture_output=True)
processNames = subprocess.run(['grep', 'process_name'],
input=ps.stdout, capture_output=True)
print(processNames.stdout.decode('utf-8').strip())
9 Comments
capture_output will only work for Python 3.7.9 and above.check do and what's the purpose of capture_output?capture_output is a shorthand for the option combination stdout=supprocess.PIPE, stderr=subprocess.PIPE and check=True raises an error if the subprocess did not return a success (zero) status.check=True is for example not strictly necessary but capture_output=True is for the answer to work. The reason for using these options should be included as a part of the answercapture_output will read all of the process's stdout into memory. For small programs like ps, this may be fine, but for larger analysis pipelines this should be avoided.See the documentation on setting up a pipeline using subprocess: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline
I haven't tested the following code example but it should be roughly what you want:
query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close() # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
2 Comments
Also, try to use 'pgrep' command instead of 'ps -A | grep 'process_name'
1 Comment
You can try the pipe functionality in sh.py:
import sh
print sh.grep(sh.ps("-ax"), "process_name")
4 Comments
command = "ps -A | grep 'process_name'"
output = subprocess.check_output(["bash", "-c", command])
7 Comments
shell=True and let that prepend ['sh', '-c']? Nothing in this code requires bash. (That said, it's significantly better practice to avoid using a shell at all; this use case is a reasonable one, but as soon as arguments start to get parameterized -- like taking the process_name as a parameter -- security concerns come in).subprocess.check_output(command, shell=True) doesn't require you to split the string. Popen converts any string into a list containing only that string -- thus, [command] -- so with shell=True you get ['sh', '-c'] prepended to that list, so you end up with ['sh', '-c', command], exactly what your code does here except for the sh/bash difference.shell=True, only the first element of that list would be treated as code; you'd get something like ['sh', '-c', 'ps', '-A', '|', 'grep', 'process_name']. That's not a useful thing to do: when invoked that way, the shell runs ps with $0 being -A, $1 being |, etc... but since the command ps doesn't look at $0, $1, etc., all that extra content is simply ignored.Lib/subprocess.py, you'll see that there literally is no difference between subprocess.check_output(["sh", "-c", command]) and subprocess.check_output(command, shell=True). The code is clear and simple -- this is not a place where there can be a devil hiding in the details somewhere.I'm answering an old question, because nobody mentioned the shlex.
In Unix, you can construct a command using pipes safely with the shlex.join(), like the following example.
import shlex
import subprocess
print(subprocess.check_output(
shlex.join(['ps', '-ef']) + ' | ' +
shlex.join(['grep', 'ps -ef']), # The arguments will be quoted.
shell=True
).decode('utf-8'))
Comments
I think that launching a shell just to enjoy the pipelining is not as elegant as it could be.
The following code uses native subprocess pipeline support and it works indeed.
You could easily modify it to add more than two processes to the pipeline.
#!/usr/bin/env python3
import subprocess
def ps_grep(pattern):
# First command-line
ps_command = ["ps", "-A"]
# Second command-line
grep_command = ["grep", pattern]
# Launch first process
ps_process = subprocess.Popen(ps_command, stdout=subprocess.PIPE)
# Launch second process and connect it to the first one
grep_process = subprocess.Popen(
grep_command, stdin=ps_process.stdout, stdout=subprocess.PIPE
)
# Let stream flow between them
output, _ = grep_process.communicate()
return output.decode()
if __name__ == "__main__":
print(ps_grep("python"))
psutilthat allows to get process info in a portable manner.