2

How can I use grep to find a string in files, but only search in the first line of these files?

migrated from serverfault.com Mar 24 '15 at 9:47

This question came from our site for system and network administrators.

  • 5
    grep -n . file.glob | grep "^1:.*search string" – rob Mar 23 '15 at 13:32
  • 1
    grep 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
4

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…

2

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.

1

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
0

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/;
}
0

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.

0

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 of head to prevent accidental matching against the filename. – Skippy le Grand Gourou Apr 7 '17 at 8:21
0

Try:

$ case "$(head -n 1 < file)" in (*pattern*) echo Match ;; esac
Match

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.