1)
# find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /Scanning/ { f1++ }; /GIMP/ { f2++ }; /steps/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/scanning.txt &
[1] 57904
# jobs -l
[1]+ 57904 Running find find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /Scanning/ { f1++ }; /GIMP/ { f2++ }; /steps/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/scanning.txt &
# jobs -l
[1]+ 57904 Done find find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /Scanning/ { f1++ }; /GIMP/ { f2++ }; /steps/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/scanning.txt
scanning.txt is an empty file.
If the text file is empty - it means that no files were found with ALL three of the search terms in them.
2)
# find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /epson/ { f1++ }; /3490/ { f2++ }; /ubuntu/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/epson_3490.txt &
[1] 84072
# jobs -l
[1]+ 84072 Running find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /epson/ { f1++ }; /3490/ { f2++ }; /ubuntu/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/epson_3490.txt &
#
[1]+ Done find /path/to/storage/hard-drive/ -name "*.txt" -type f -exec awk 'FNR == 1 { f1=f2=f3=0; }; /epson/ { f1++ }; /3490/ { f2++ }; /ubuntu/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' {} \; > /tmp/epson_3490.txt
# cat /tmp/epson_3490.txt
~/PC1A_1TB_Daily_Working_Doc_20180926/epson_scanner_20180116.txt
~/Ubuntu_Desktop_7.10/scanner_20071230.txt
~/Reference_Misc/url_20080109.txt
~/Computer_and_Hardware_20121105_20200131/scanning_n_scanner_20140902.txt
......
etc.
It works here. Thanks
Great news!
Would it be possible to find files with a pattern, example;
<FilesMatch '.(php|php5|suspected|py|phtml)$'>
Order allow,deny
Deny from all
</FilesMatch>
Didn't I answer this in another thread?
Please help me to learn the function of;
1)
{ print FILENAME; nextfile; }' {}
2)
f1 && f2 && f3 { print FILENAME; nextfile; }
1)
{ print FILENAME; nextfile; }
That prints the FILENAME for the file that awk is reading and then moves on to the next file.
2)
f1 && f2 && f3 { print FILENAME; nextfile; }
The first part means "If f1 AND f2 and F3 are not zero, then print the file-name for the current file and move onto the next file.
f1, f2 and f3 are counter variables in the awk-script that gets ran by find. These are used to count the number of instances of each search term.
If I rewrite the one-liner to take up several lines, perhaps it will make a little more sense to you:
Bash:
find /path/to/search -type f -name "*.txt" -exec awk '
FNR == 1 { f1=f2=f3=0; };
/epson/ { f1++ };
/3490/ { f2++ };
/ubuntu/ { f3++ };
f1 && f2 && f3 { print FILENAME; nextfile; }
' {} \; > /tmp/epson_3490.txt &
Note: This is just for illustrative purposes.
I wouldn't advise entering the one-liner over several lines like this.
This is just to show you step by step what is going on.
So the first line contains the bulk of the find command:
find /path/to/search -type f -name "*.txt" -exec awk '
So in the above, we have a find command that is searching for .txt files. For each .txt file that is found, the -exec will run awk. The single quote is the start of the awk script.
The second line is the first part of the awk script:
FNR == 1 { f1=f2=f3=0; };
FNR is the line-number of the file we're reading.
If the line number is 1 (i.e. we're reading the first line of a file) - Then we set up three counter variables and initialise them to zero.
So each time we start reading a new file, the counters are reset to zero.
The next three lines are our search patterns and the actions to take when each pattern is found:
Code:
/epson/ { f1++ };
/3490/ { f2++ };
/ubuntu/ { f3++ };
So every time "epson" is found, the value of f1 is increased by 1.
Likewise, every time "3490" is found, the value of f2 is increased by 1.
And every time "ubuntu" is found, f3 is increased by 1.
The next line has already been explained:
f1 && f2 && f3 { print FILENAME; nextfile; }
If f1 AND f2 AND f3 are not zero, then we got at least one match in the file for each search term. So the file contains all three search terms. In which case, we print/output the filename and then move to the next file.
It's also worth noting that all of the actions - the line number check, the three searches and the check on f1, f2 and f3 are performed on each line in the file. So as soon as all three counter variables are greater than zero - awk will move to the next file. Which means that each matching file doesn't have to be read until the very end. As soon as it has been determined that the file matches all of the patterns, awk outputs the file-name and moves to the next file. After moving to the next file - when the first line is read, the counters will be re-initialised to zero.
Non-matching files will be read until the end, so it only really speeds up the reading of the matching files. But it is a small optimisation that will speed things up a tiny bit.
The final line:
' {} \; > /tmp/epson_3490.txt &
The single quote at the start of the line is the end of the awk script.
The
{} \;
is the remainder of find's -exec section.
The
{}
is a placeholder which find uses to substitute in the file-names into for the files found by find. So those filenames are passed to the awk command. They are the files that awk acts upon. The
\;
denotes the end of the find commands -exec section.
The rest of the line:
> /tmp/epson_3490.txt &
is the redirection to the output file and the final ampersand runs the job in the background.
Hopefully breaking the command down like that makes things a little easier to understand?!