Reputation: 327
I have a file
foo
--
bar
I only want the lines above the separator. I've struggled with this for too long and tried a number of variants. My one liner is:
echo -e "foo\n-- \nbar" | gawk -v x=0 -- '/^--\ / { x++ } ; IF (x==0) {print} '
This should print only "foo" but I get the whole file output. If I change to print x I get
0
1
1
I can't seem to make make awk conditionally print a line based on the value of x. I know I am missing something simple.
Upvotes: 4
Views: 4535
Reputation: 203139
In GNU awk you could just set the record separator to be a line that only contains "--" and then just print the first record:
$ gawk -v RS='\n--\n' 'NR==1' file
foo
or if performance is a concern:
$ gawk -v RS='\n--\n' 'NR==1{print;exit}' file
foo
that way you can enhance the script later to print any other record you might want:
$ cat file
the
quick
--
brown
fox
--
jumped
$
$ gawk -v RS='\n--\n' 'NR==1' file
the
quick
$ gawk -v RS='\n--\n' 'NR==2' file
brown
fox
$ gawk -v RS='\n--\n' 'NR==3' file
jumped
Upvotes: 1
Reputation: 46813
If you like sed
better:
sed -n '/^--$/q;p' file.txt
Explanation: sed
reads the file line by line. If sed finds the pattern ^--$
(i.e., a line that contains exactly --
) it quits (that's the q
command), otherwise, sed
prints out the content of that line (with the p
command). Note that sed
was launched with the -n
option, i.e., doesn't output anything unless explicitly told to with the p
command. Since sed
quits when the separator --
is found (i.e., before the p
command), this separator will not be printed.
The good thing about sed
is that it's faster than awk
for this task.
Edit. As glenn jackman points out in a comment, with GNU sed, you can use:
sed '/^--$/Q' file.txt
(I wasn't on a computer that had a sed
with the Q
command when I answered). Thanks glenn.
Upvotes: 2
Reputation: 184965
Try doing this :
echo -e "foo\n-- \nbar" | awk '/^--/{exit}1'
EXPLANATIONS
/^--/
is a regex to match the string at the beginning of the current line{}
part is executed if the condition is true (the previous regex)1
is like {print}
: by default, awk
print on STDOUT if a condition is true. While 1
is true for awk, it print the current line.Decomposition of the command :
echo -e "foo\n-- \nbar" | awk '
{
if (/^--/) {
exit
}
else {
print
}
}
'
Alternative decomposition:
echo -e "foo\n-- \nbar" |
awk '(/^--/) { exit }
{ print }'
This emphasizes that there are two pattern-action rules; one with an explicit pattern and an exit action; the other with implicit pattern and print action.
Upvotes: 5
Reputation: 753465
Your original script was on the right lines but too complex:
echo -e "foo\n-- \nbar" | gawk '/^--\ / { x++ } { if (x==0) print}'
Variables are automatically created and zeroed by awk
(so you don't need -v x=0
etc). The 'spot the double dash' code was fine. The semi-colon is unnecessary (at best). The IF (x == 0) {print}
is plain weird. The awk
on Mac OS X 10.7.5 accepts it, but I'm not sure what it was doing. The replacement action is for every line, and tests whether x
is zero before printing.
Personally, I'd probably use sed
for this:
echo -e "foo\n-- \nbar" | sed '/^--/q'
Fixing my sed
command as gniourf_gniourf suggests:
echo -e "foo\n-- \nbar" | sed -n '/^--/q;p'
You can mimic that in awk
with the command shown by sputnick in his answer.
echo -e "foo\n-- \nbar" | awk '/^--/ {exit} 1'
The 1 matches every line (it is always true) and triggers the default action, which is 'print $0'. You could also write:
echo -e "foo\n-- \nbar" | awk '/^--/ {exit} {print}'
Upvotes: 1