Better to explain on examples.

I can:

find . -name "*.py" -type f > output.txt

But how can I store the output to the same file for:

find . -name "*.py" -type f -exec grep "something" {} \

I can't just do

find . -name "*.py" -type f -exec grep "something" {} \ > output.txt
up vote 91 down vote accepted

If I understand you correctly this is what you want to do:

find . -name '*.py' -print0 | xargs -0 grep 'something' > output.txt

Find all files with extension py, grep only rows that contain something and save the rows in output.txt. If the file contains anything it will be replaced.

Edit: Using -exec:

find . -name '*.py' -exec grep 'something' {} \; > output.txt

I'm incorporating Chris Downs comment here. The above command will result in grep being executed as many times as find finds occurences. However, if you replace the ; with a +, grep is called with the output from find concatenated (up to a certain limit). See question Using semicolon (;) vs plus (+) with exec in find for more on the subject.

  • 13
    Use + instead of \;, it will improve execution time significantly (since it will contatenate arguments prior to execution until ARG_MAX). – Chris Down Nov 6 '11 at 14:31
  • Now I understand the power of xargs! Thanks! – domih Apr 6 '16 at 8:45
  • 2
    Usegrep -H if you want to include the filename of the file in the output. – Steinar Apr 23 at 13:18

If you want to save all the matching lines across all files in output.txt, your last command does work, except that you're missing the required ; at the end of the command.

find . -name "*.py" -type f -exec grep "something" {} \; > output.txt

If you want each run of grep to produce output to a different file, run a shell to compute the output file name and perform the redirection.

find . -name "*.py" -type f -exec sh -c 'grep "something" <"$0" >"$0.txt"' {} \;
  • the last one really nice :D – bakytn Sep 20 '11 at 3:32
  • To expand on @gilles answer to make it a little more informative, especially if the list of files you're dealing with is large, you can report the file name (relative path) of each file along with the grep'ed results using this: find . -name "*.py" -type f -exec grep "something" {} \; -print > output.txt And if you'd like to see the line numbers of the grep'ed lines you can, of course, use grep -n "something" – JJMpls Jul 24 '14 at 2:27

For the record, grep has --include and --exclude arguments that you can use to filter the files it searches:

grep -r --include="*.py" "something" > output.txt
  • 1
    At least GNU grep does. – phk Nov 1 '16 at 20:43

Use tee:

find . -name '*.py' | tee output.txt | xargs grep 'something'

The caveat, is if you have any files with special characters (including spaces) that xargs and grep won't work well with (a file.txt will be interpreted as two files, a and file.txt). The alternative to that is to use either the -x or -print0, but either of those will pollute your output.txt. The -x will use \ to escape certain special characters and this will be in output.txt. The -print0 will use a null byte as a field separator (which also requires xargs -0) and output.txt will look like one long contiguous line of text.

How you deal (or don't) with this is up to you.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.