Here's an overview of different methods that one can use for searching files for specific strings of text, with a few options added specifically to work only with text files, and ignore binary/application files.
One should note,however,that searching for word can get a little complex, because most line-matching tools will try to find a word anywhere on the line. If we're talking about a word as string that could appear in the beginning or end of line, or alone on the line, or surrounded by spaces and/or punctuation - that's when we'll need regular expressions, and especially those that come from Perl. Here, for example, we can use -P
in grep
to make use of Perl regular expressions to surround it.
$ printf "A-well-a don't you know about the bird?\nWell, everybody knows that the bird is a word" | grep -noP '\bbird\b'
1:bird
2:bird
Simple grep
$ grep -rIH 'word'
-r
for recursive search down from current directory
-I
to ignore binary files
-H
to output filename where match is found
Suitable for searching only.
find + grep
$ find -type f -exec grep -IH 'word' {} \;
find
does the recursive search part
-I
option is to ignore binary files
-H
to output filename where line is found
good approach for combining with other commands within subshell, like:
$ find -type f -exec sh -c 'grep -IHq "word" "$1" && echo "Found in $1"' sh {} \;
Perl
#!/usr/bin/env perl
use File::Find;
use strict;
use warnings;
sub find_word{
return unless -f;
if (open(my $fh, $File::Find::name)){
while(my $line = <$fh>){
if ($line =~ /\bword\b/){
printf "%s\n", $File::Find::name;
close($fh);
return;
}
}
}
}
# this assumes we're going down from current working directory
find({ wanted => \&find_word, no_chdir => 1 },".")
poor-mans recursive grep in recursive bash script
This is the "bash way". Not ideal, probably no good reason to use this when you have grep
or perl
installed.
#!/usr/bin/env bash
shopt -s globstar
#set -x
grep_line(){
# note that this is simple pattern matching
# If we wanted to search for whole words, we could use
# word|word\ |\ word|\ word\ )
# although when we consider punctuation characters as well - it gets more
# complex
case "$1" in
*word*) printf "%s\n" "$2";;
esac
}
readlines(){
# line count variable can be used to output on which line match occured
#line_count=1
while IFS= read -r line;
do
grep_line "$line" "$filename"
#line_count=$(($line_count+1))
done < "$1"
}
is_text_file(){
# alternatively, mimetype command could be used
# with *\ text\/* as pattern in case statement
case "$(file -b --mime-type "$1")" in
text\/*) return 0;;
*) return 1;;
esac
}
main(){
for filename in ./**/*
do
if [ -f "$filename" ] && is_text_file "$filename"
then
readlines "$filename"
fi
done
}
main "$@"