Al_Mt
Al_Mt

Reputation: 167

How to print the file names from which I grep some lines

I'm trying to get some lines from several json files using the following code:

cat $(find ./*/*/folderA/*DTI*.json) | grep -i -E '(phaseencodingdirection|phaseencodingaxis)' > phase_direction

It worked! the problem is that I don't know which line comes from which file

With this find ./*/*/preprocessing/*DTI*.json -type f -printf "%f\n" I can print those names, but they appear at the end and not in order with their respective phaseencodingdirection|phaseencodingaxis extracted lines.

I don't know how to combine those lines of code to print the file's name from which the line was extracted and their respective extracted lines!?

Could you help me?

Upvotes: 1

Views: 1391

Answers (3)

John Bollinger
John Bollinger

Reputation: 180161

the problem is that I don't know which line comes from which file

Well no, you don't, because you have concatenated the contents of all the files into a single stream. If you want to be able to identify at the point of pattern matching which file each line comes from then you have to give that information to grep in the first place. Like this, for example:

find ./*/*/folderA/*DTI*.json |
        xargs grep -i -E -H '(phaseencodingdirection|phaseencodingaxis)' > phase_direction

The xargs program converts lines read from its standard input into arguments to the specified command (grep in this case). The -H option to grep causes it to list the filename of each match along with the matching line itself.

Alternatively, this variation on the same thing is a little simpler, and closer in some senses to the original:

grep -i -E -H '(phaseencodingdirection|phaseencodingaxis)' \
    $(find ./*/*/folderA/*DTI*.json) > phase_direction

That takes xargs out of the picture, and moves the command substitution directly to the argument list of grep.

But now observe that if the pattern ./*/*/folderA/*DTI*.json does not match any directories then find isn't actually doing anything useful for you. There is then no directory recursion to be done, and you haven't specified any tests, so the command substitution will simply expand to all the paths that match the pattern, just like the pattern would do if expanded without find. Thus, this is probably best of all:

grep -i -E -H '(phaseencodingdirection|phaseencodingaxis)' \
    ./*/*/folderA/*DTI*.json > phase_direction

Upvotes: 2

anubhava
anubhava

Reputation: 785058

You may use recursive grep:

grep -iER 'phaseencodingdirection|phaseencodingaxis' --include=*DTI*.json */*/folderA

Upvotes: 0

Barmar
Barmar

Reputation: 780851

Use the filenames as arguments to grep rather than cat.

grep -i -H -E '(phaseencodingdirection|phaseencodingaxis)' $(find ./*/*/folderA/*DTI*.json) > phase_direction

The -H option forces grep to incliude filenames in the output even if there's only one file.

But since your arguments to find are filenames, not directories to search recursively, there's no need to use it at all. Just pass the wildcard directly to grep. There's also no need to begin with ./. Any non-absolute pathname is interpreted relative to the current directory.

grep -i -H -E '(phaseencodingdirection|phaseencodingaxis)' */*/folderA/*DTI*.json > phase_direction

Upvotes: 1

Related Questions