I want to search my code base for ocurrences of a string, and then get the formatted output as filename, line number, and code lide. I got it as I wanted on the first line of the output, but the coming lines loses the wanted formatting.

$ find src/ -name "*.js" | xargs grep --null -E -n 'filter\(|map\(' | xargs -0 printf "%-100s%-5s%-100s" > test.txt

The output is as follows: (scroll right to see the complete line)

src/components/AppRouterSwitch.js                                                                   15:    return _Routes.map((route, index) => {
src/components/forms/UserEditForm/UserEditForm.js36:    const options = UserTypes.map((type, index) => <option key={index} value={type.type}>{type.name}</option>);
src/components/pages/AdminPage/SolutionManagementEditPage/SolutionManagementEditPage.js119:        templates:state.templates.filter(item=>item.SOLUTIONID ==id)
src/components/pages/AdminPage/SolutionManagementEditPage/SolutionManagementEditPage.js120:            .map(item=>{return{

The first row looks just as I want it. The following loses the desired formatting. Ending the printf format string with /n doesn't do the trick.

  • 1
    Try to use the standard option of grep -l (a lowercase L) – malyy Nov 13 '18 at 9:59
  • 1
    @malyy I tried that with some variations but no success. I don't see how the -l option would help me. -l, --files-with-matches Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match. – Max Nov 13 '18 at 10:08
  • please check my answer and clarify if you really want the colon (:) after the line number – qubert Nov 13 '18 at 14:03
find src/ -type f -name '*.js' -exec grep -Hn -E -- 'filter\(|map\(' {} + |
    awk -F: '{printf "%-100s%-5s%-100s\n", $1, $2, substr($0, length($1) + length($2) + 3)}'

The -H option to grep will cause it to print the filename even when called with a single file as argument. The -type f option to find is needed in order to skip broken links and directories that happen to be named *.js.

Or even simpler, get rid of grep completely (thanks to @don_crissti for the suggestion):

find src/ -type f -name '*.js' -exec awk '/filter\(|map\(/{printf "%-100s%-5s%-100s\n", FILENAME, FNR, $0}' {} +
  • Elegant solution, just what I needed. The colon is not necessary. – Max Nov 13 '18 at 19:22

man makes it a bit unclear. "The scanning will stop on the first match" - indicates that all file names will be printed, but the scanning for the matching word will stop at the first occurence. GNU grep man page clarifies this:

Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning of each file stops on the first match. (-l is specified by POSIX.)

Here is an example:

$grep -iR Intel * 
2018/jan/cpu.txt:Intel i9 
2018/motherboard.txt:Intel Motherboard 
hardware.txt:Intel Corei7
#the same result as you provided;

$grep -iRl Intel * 
#the desired result
  • Not quite what I wanted. Please scroll the output to the right and you'll se that I also want line number and line of code, but formatted as on the first row. – Max Nov 13 '18 at 12:08

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.