11

I am writing a script, I want to check if the first line of the file matches a certain pattern and if it does then print out the file. How can I achieve this?

How do I check for pattern? Is there a way to check for pattern and based on the output do something..

EDIT: Please take a look at this question: https://stackoverflow.com/questions/5536018/how-to-get-match-regex-pattern-using-awk-from-file

I want something like this, but none of them worked for me. I basically want to check if the first line matches a regex pattern or not and based on that print the lines of file.

Mathew
  • 145
  • 1
  • 10

5 Answers5

17

You could do that with ed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

the trick here is to try to replace PATTERN on 1st line with itself. ed will error out if it can't find the specified pattern so ,p (print whole file) will only be executed if 1s/PATTERN/&/ is successful.

Or with sed:

sed -n '1{
/PATTERN/!q
}
p' infile

this quits if the first line does not (!) match PATTERN, otherwise it prints all lines.
Or, as pointed out by Toby Speight, with GNU sed:

sed '1{/PATTERN/!Q}' infile

Q is the same as q but it does not print the pattern space.

don_crissti
  • 82,805
15

With POSIX tools chest:

{ head -n 1 | grep pattern && cat; } <file
cuonglm
  • 153,898
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

would print the name of the non-hidden txt files in the current directory whose first line matches the extended regular expression pattern with those awk inplementations that support nextfile.

If instead of printing the file name, you want to print the whole file content, you can do:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

That's efficient in that it runs only one command, but awk being not the most efficient command to dump the content of a file, with large files, you could possibly obtain better performances by doing something like:

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

That is, only use awk to print the list of files that match (0-delimited) and rely on cat to dump their content.

6

If you're writing a shell script, you could so something like

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

Or, in Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
terdon
  • 242,166
  • @Stéphane Chazelas: Maybe close ARGV is more idiom than assigning to $.. – cuonglm Sep 29 '15 at 10:58
  • @terdon Yours looks like code golf, all in one line, no brackets around the variable names and is not encouraging clean structure. And you had a missing dollar sign when I posted, that's just not the way to teach bash. I assume those factors come from the perl background you also seem to have, so you shall be forgiven! ;) –  Sep 29 '15 at 21:01
  • @guest hi and welcome to the site! I converted your answer to a comment since answers should only be posted if they are answering the actual question. This is not a forum in the classic sense and we only want pure Q&A here. You might want to take a look at the [help] or take the [tour] to understand the site better. That said, my background is actually in biology so yes, my code is far from clean :) However, I don't see how brackets would help here, the quotes already protect the variable. What would break this that brackets would protect from? – terdon Sep 29 '15 at 21:33
  • @guest ah, sorry, forgot you can't comment. Feel free to come and explain in chat, I'm sure I might learn something. – terdon Sep 29 '15 at 21:34
5

Oldschool, just translate your sentence into standard commands:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

For learning bash that is a good start. If you just need a quick solution, try the sed-, awk- or perl-answers. Both nice, but they are own languages you need (and probably want) to learn.

It's a pretty simple example, so if you want to learn more, you could also try the same in ruby, php, js (e.g. in nodejs) or any other language that allows file access. Even C/C++ or Java should be easy to manage with a small task.

guest
  • 51
  • 1