Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Subprocess Grep

I am trying to use the grep command in a python script using the subprocess module.

Here's what I have:

userid = 'foo12'
p = subprocess.Popen(['grep', "%s *.log"%userid], stdout=subprocess.PIPE)

And it returns nothing. I am not entirely sure what I am doing wrong so can someone please explain. The current method that I am using that works is by adding the shell=true which makes it output the correct output but as the help pages have pointed out it is unsafe. I need help trying to make this work so that my script isn't unsafe.

like image 684
Jason Zhu Avatar asked Oct 31 '11 16:10

Jason Zhu


People also ask

How do you grep in python?

To search a file employing grep in Python, import the “re” package, upload the file, and use a for loop to iterate over each line. On each iteration, use the re.search() method and the RegEx expression as the primary argument and the data line as the second.

What is subprocess Check_output in Python?

The subprocess. check_output() is used to get the output of the calling program in python. It has 5 arguments; args, stdin, stderr, shell, universal_newlines. The args argument holds the commands that are to be passed as a string.

How use subprocess command with pipes?

To use a pipe with the subprocess module, you have to pass shell=True . In your particular case, however, the simple solution is to call subprocess. check_output(('ps', '-A')) and then str. find on the output.

What is Shell true in subprocess python?

Setting the shell argument to a true value causes subprocess to spawn an intermediate shell process, and tell it to run the command. In other words, using an intermediate shell means that variables, glob patterns, and other special shell features in the command string are processed before the command is run.


1 Answers

I think you're running up against two problems:

  1. This call:

    p = subprocess.Popen(['grep', "%s *.log"%userid]...
    

    will not work as expected without shell=True because the list of arguments are being passed directly to os.execvp, which requires each item to be a single string representing an argument. You've squished two separate arguments together into a single string (in other words, grep is interpreting "foo12 *.log" as the pattern to search, and not pattern+file list).

    You can fix this by saying:

    p = subprocess.Popen(['grep', userid, '*.log']...)
    
  2. The second issue is that, again without shell=True, execvp doesn't know what you mean by *.log and passes it directly along to grep, without going through the shell's wildcard expansion mechanism. If you don't want to use shell=True, you can instead do something like:

    import glob
    args = ['grep', userid]
    args.extend(glob.glob('*.log')
    p = subprocess.Popen(args, ...)
    
like image 57
bjlaub Avatar answered Oct 04 '22 02:10

bjlaub