I'd like to find all the Java files containing keyword File.createTempFile with the line number. Here's what I did:

$ find . -name "*.java" | xargs grep -n "File.createTempFile"
./nuxeo-studio-test/src/test/java/com/nuxeo/studio/web/StudioServletTest.java:162:            File tmpFile = File.createTempFile(jarEntryName, null, Environment.getDefault().getTemp());
./nuxeo-studio-ui/src/main/java/com/nuxeo/studio/core/builders/WorkflowFeatureBuilder.java:421:            tmp = File.createTempFile(".workflow-to-zip", ".tmp", workspace.getRoot());
./nuxeo-studio-ui/src/test/java/com/nuxeo/studio/core/backup/TestS3Backup.java:101:        File tempFile = File.createTempFile(RandomStringUtils.randomAlphabetic(5), ".tmp");
./nuxeo-studio-ui/target/classes/com/nuxeo/studio/core/builders/WorkflowFeatureBuilder.java:421:            tmp = File.createTempFile(".workflow-to-zip", ".tmp", workspace.getRoot());
./nuxeo-studio-web/src/main/java/com/nuxeo/studio/web/v1/ProjectResource.java:191:            File zip = File.createTempFile(filename + "-", ".zip", tempRepo);

However, I found this result too long to read. I'd like to keep only the file path and the line number. Here's expected result:


Could somebody teach me how to do so?

  • Use grep -L or pipe your output to awk '{ print $1 }'. The later won't work with file paths that contain spaces.
    – jordanm
    Mar 13 '17 at 14:40
  • @jordanm, the 2nd solution works fine: it contains additional :, but it's good enough. I cannot use the first one successfully, could you give the full command? Mar 13 '17 at 14:49

With pcregrep, you could do:

pcregrep --include='\.java$' -rHno1 '()File\.createTempFile' .

The output will be looking like:


If the pattern appears more than once on a line, there will be as many lines output. If you don't want that, you could change it to:

pcregrep --include='\.java$' -rHno1 '^().*?File\.createTempFile' .

Here's one way with awk:

find . -name '*.java' -exec awk '/PATTERN/{print FILENAME,FNR}' {} +

or, if you wanted to emulate grep's output:

find . -name '*.java' -exec awk '/PATTERN/{printf("%s:%s\n", FILENAME, FNR)}' {} +
find . -type f -name '*.java' -exec perl -slne '
  print "$ARGV:$." if /\Q$k\E/; $. = 0 if eof;
' -- -k="$keyW" -- {} +
  • The results found are correct, but their line numbers are wrong: the number shown refers to the file index in the result. Mar 13 '17 at 14:53
  • You'll need to not use {} + to avoid the xargs grouping, or tell perl to reset the line number between files, see perldoc -f eof for details.
    – thrig
    Mar 13 '17 at 15:15
  • @Thrig+Mincong: Thanks for spotting the error. Fixed it.
    – user218374
    Mar 13 '17 at 15:56

Just filter out the part you don't want:

grep -n … | cut -d : -f 1,2

(This assumes that your file names don't contain colons or newlines.)

esport keyW='File.createTempFile'
find . -name '*.java' -type f -exec sh -c '
   grep -hn "$keyW" "$1" | cut -d":" -f1 |
   while IFS=: read -r n x; do
      printf "%s:%s\n" "$1" "$n"
' {} {} \;


grep has to be run 1/per file is the limiation for this method.

  • Not sure why, but the print '%s:%s\n' "$1" "$n" does not add linefeed \n correctly, even if I change it to \\n. So all the results are correct, but displayed in a single line. Mar 13 '17 at 20:07
  • Make them to be double quotes: like printf "%s:%s\n" "$1" "$n"
    – user218374
    Mar 13 '17 at 20:16
  • Yes, it works now. Mar 13 '17 at 20:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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