Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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: http://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.

share|improve this question
    
What is the output you're expecting? What is the pattern you're looking for? What have you tried so far? –  tachomi yesterday
    
@tachomi edited please take a look –  Mathew yesterday
    
@Mathew - please don't change the requirement after getting several answers that address your initial requirement. If you want to delete a file if the first line doesn't match some pattern please ask a new question. –  don_crissti 5 hours ago

5 Answers 5

up vote 12 down vote accepted

You could do that 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.

share|improve this answer
    
You could Q instead of q for GNU sed, or d before q (portable) so as not to require the -n flag and p command: sed '1{/PATTERN/!Q}' infile or sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, respectively. –  Toby Speight 9 hours ago
    
@TobySpeight - re:Q - you're right though my answer wasn't meant to be GNU sed specific but was edited by Stéphane due to the fact I used gnu sed syntax for the one-liner... re: d before q - no, it doesn't work because if d is executed then q is never executed (d restarts the command cycle). –  don_crissti 9 hours ago

With POSIX tools chest:

{ head -n 1 | grep pattern && cat; } <file
share|improve this answer
1  
{ double } <sweet. –  mikeserv 23 hours ago
    
@mikeserv: I intend to use it to prevent new person from confusing, but Stephane edited is clearer. –  cuonglm 16 hours ago

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' ./*
share|improve this answer
    
@Stéphane Chazelas: Maybe close ARGV is more idiom than assigning to $.. –  cuonglm 15 hours ago
    
@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! ;) –  guest 5 hours ago
    
@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 center 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 4 hours ago
    
@guest ah, sorry, forgot you can't comment. Feel free to come and explain in chat, I'm sure I might learn something. –  terdon 4 hours ago
 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.

share|improve this answer

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.

share|improve this answer
1  
This is basically the same as mine except that you use if/else instead of [ ] &&. –  terdon 15 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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