3

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:

./nuxeo-studio-test/src/test/java/com/nuxeo/studio/web/StudioServletTest.java:162
./nuxeo-studio-ui/src/main/java/com/nuxeo/studio/core/builders/WorkflowFeatureBuilder.java:421
./nuxeo-studio-ui/src/test/java/com/nuxeo/studio/core/backup/TestS3Backup.java:101
./nuxeo-studio-ui/target/classes/com/nuxeo/studio/core/builders/WorkflowFeatureBuilder.java:421
./nuxeo-studio-web/src/main/java/com/nuxeo/studio/web/v1/ProjectResource.java:191

Could somebody teach me how to do so?

don_crissti
  • 82,805
  • 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? – Mincong Huang Mar 13 '17 at 14:49

5 Answers5

3

With pcregrep, you could do:

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

The output will be looking like:

./path/to/file.java:12:

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' .
2

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)}' {} +
don_crissti
  • 82,805
2
keyW='File.createTempFile'
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. – Mincong Huang 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. –  Mar 13 '17 at 15:56
1
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"
   done
' {} {} \;

Notes:

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

1

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.)