How can I use grep to find a string in files, but only search in the first line of these files?
-
5grep -n . file.glob | grep "^1:.*search string" – rob Mar 23 '15 at 13:32
-
1grep root <(head -1 /etc/passwd) – c4f4t0r Mar 23 '15 at 14:07
-
It's probably easiest to write a perl 1-liner to do this, otherwise it would have to be a hacky combination of head and grep. – Sig-IO Mar 23 '15 at 14:39
-
1@peterh Rather than asking the question again, it is better to flag the current question for migration there. – kasperd Mar 23 '15 at 15:25
-
Is there a reason you have to use grep? Rather than, say sed or awk? – Toby Speight Apr 7 '17 at 8:32
Two more alternatives :
With awk
awk '{if ($0~"pattern") print $0; nextfile;}' mydir/*
or if your awk
version doesn't support nextfile
(thanks to Stéphane Chazelas for the suggestion) :
awk 'FNR==1{if ($0~"pattern") print $0;}' mydir/*
will read only the first line before switching to next file, and print it only if it matches "pattern"
.
Advantages are that one can fine-tune both the field on which to search the pattern for (using e.g. $2
to search on the second field only) and the output (e.g. $3
to print the third field, or FILENAME
, or even mix).
Note that with the FNR
("current input record number", i.e. line number) version you can fine-tune further the line(s) on which you want to grep : FNR==3
for the third line, FNR<10
for the 10 first lines, etc. (I guess in this case, if you are dealing with very large files and your awk
version supports it you may want to mix FNR
with nextfile
to improve performances.)
With head
, keeping filenames
head -n1 -v mydir/files*|grep -B1 pattern
-v
option of head
will print filenames, and option -B1
of grep
will print the previous line of matching lines — that is, the filenames. If you only need the filenames you can pipe it further to grep
:
head -n1 -v mydir/*|grep -B1 pattern|grep ==>
As noticed by don_crissti in comments, beware of filenames matching the pattern themselves, though…
I have implemented the comment of @Rob and succeeded to get the desired result.
Replace string
by your string.
grep -Rin "string" . | grep ":1:.*string" > result.txt
This does a recursive case-insensitive search for string
in the current directory and prints the line numbers. Then it searches for occurrences in files which are on line 1 and saves the output to a file called result.txt
.
Here is a perl onliner to do just that
perl -ne 'print if /MY_SEARCH_STRING/; exit' myfile.txt
This is going to check if the keyword MY_SEARCH_STRING
is present in the first line of the file myfile.txt
. If you need to search in the entire file just remove exit
from the oneliner.
-
Note that one needs to loop on the list of files if there are several. That is, globbing (using wildcard, e.g.
mydirectory/*
) won't work. – Skippy le Grand Gourou Apr 6 '17 at 13:44
Here is a (bad) example of a perl-script that would do something like this:
#!/usr/bin/perl -w
foreach (@ARGV) {
my $filename = $_;
open my $file, '<', $filename;
my $line = <$file>;
close $file;
print "$filename\n" if $line =~ /your-match-text/;
}
Try something like this. Create file finder.sh with this content. Change parameters in the file to fit your needs.
#!/bin/bash
# Where to search
DIR="/path/search/dir"
# Search string
SEARCH="my-string"
FILES=$(find "$DIR" -type f)
for F in $FILES; do
head -1 $F | grep -w "$SEARCH"
done
Save the file and chmod +x finder.sh
Execute ./finder.sh
Note: if you going to search in files with root privileges you need to use sudo or root user.
Do you want the list of full strings as a result, or do you want a list of files that contain the string? This would search line number one(-n1) of shell scripts(*.sh) and collect the strings containing 'bash':
head -n1 *.sh | grep bash > fullstring.txt
fullstring.txt would contain something like this:
#!/bin/bash
#!/bin/bash
-
Beware, better use the
-q
option ofhead
to prevent accidental matching against the filename. – Skippy le Grand Gourou Apr 7 '17 at 8:21