Method #1
You could use the following chain:
$ grep -l stringA * | tr '\n' '\0' | xargs -0 grep -l stringB | xargs du | sort -nr
The tr
converts the output of grep
so that if any filenames include spaces they'll be protected going forward. Everything else is pretty straight-forward. The use of xargs
to run the output from a previous command through the next command, is a typical pattern in Unix.
You can forego the tr
bit and make use of grep
's -Z
switch.
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs du | sort -nr
Example
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs du | sort -nr
9220 stringA99stringB.txt
8196 stringA88stringB.txt
7172 stringA77stringB.txt
6148 stringA66stringB.txt
5124 stringA55stringB.txt
4100 stringA44stringB.txt
3076 stringA33stringB.txt
2052 stringA22stringB.txt
1028 stringA11stringB.txt
4 stringAspacestringB.txt
Method #2
Similar approach except instead of the use of du | sort
just pipe the output to ls -lS
similar to your approach.
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs ls -lS
Example
$ grep -lZ stringA * | xargs -0 grep -l stringB | xargs ls -lS
-rw-rw-r-- 1 saml saml 9437200 Aug 6 15:15 stringA99stringB.txt
-rw-rw-r-- 1 saml saml 8388624 Aug 6 15:15 stringA88stringB.txt
-rw-rw-r-- 1 saml saml 7340048 Aug 6 15:15 stringA77stringB.txt
-rw-rw-r-- 1 saml saml 6291472 Aug 6 15:15 stringA66stringB.txt
-rw-rw-r-- 1 saml saml 5242896 Aug 6 15:15 stringA55stringB.txt
-rw-rw-r-- 1 saml saml 4194320 Aug 6 15:15 stringA44stringB.txt
-rw-rw-r-- 1 saml saml 3145744 Aug 6 15:15 stringA33stringB.txt
-rw-rw-r-- 1 saml saml 2097168 Aug 6 15:15 stringA22stringB.txt
-rw-rw-r-- 1 saml saml 1048592 Aug 6 15:15 stringA11stringB.txt
-rw-rw-r-- 1 saml saml 32 Aug 6 15:35 stringAspacestringB.txt
Method #3
This one makes use of grep
's ability to use Perl's regular expression engine (PCRE).
$ grep -Pzol "(?s)stringA.*stringB" * | xargs ls -lS
This method is a bit slower because the file is being converted so that it's end of lines are terminated with null characters (\0
) instead of newlines (\n
).
-P
activate perl-regexp for grep (a powerful extension of regular extensions)
-z
suppress newline at the end of line, substituting it for null character. That is, grep knows where end of line is, but sees the input as one big line.
-o
print only matching. Because we're using -z
, the whole file is like a single big line, so if there is a match, the entire file would be printed; this way it won't do that.
In regexp:
(?s)
activate PCRE_DOTALL, which means that .
finds any character or newline
References
find -iname '*.txt' | xargs grep -ne str1 -e str2
. – ott-- Aug 6 '13 at 18:45