5

Each line in a comma-separated file has 5 fields.

a,b,c,d,e
f,g,c,i,
j,k,c,m,n
o,p,c,r,s
t,u,c,w,
x,y,z,aa,bb

How can I extract the lines which have c in the 3rd field and their 5th field is NOT empty? The result would be:

a,b,c,d,e
j,k,c,m,n
o,p,c,r,s
  • We always like to see, what you tried in order to help you find the solution on your own. Otherwise it looks like you want to us to solve your homework for you. – Minix May 30 '15 at 22:25
8

Possible solution with awk:

awk -F',' '$3 == "c" && $5' file

Depending on actual data this may not work as desired as mentioned in comments (thanks Janis for pointing this: it will miss f,g,c,i,0 e.g 5th field is 0) so you can do following:

awk -F',' '$3 == "c" && $5 != ""' file

And as this is the accepted answer I am adding not so obvious forcing 5th field to string (as in cuonglm(+1) solution):

awk -F',' '$3 == "c" && $5""' file
  • 4
    Note that, depending on the actual data, this may not work as desired. It would not match f,g,c,i,0, i.e. with a 0 in the last column. The fix is of course easy: awk -F',' '$3 == "c" && $5 != "". – Janis May 31 '15 at 0:39
  • @Janis: $5"" is enough. See my answer – cuonglm May 31 '15 at 4:36
  • 1
    @cuonglm; Yes, forcing the field to string is also possible. But, IMO, it's still less clear than spending two more characters to create the explicit and (also to awk beginners!) more obvious condition $5!="". – Janis May 31 '15 at 5:20
3
sed -n '/,$/!s/^\([^,]*,\)\{2\}c/&/p'

...will work for a POSIX sed. If you can use a sed which implements AT&T Augmented regular expressions - such as the one freely available in the astopen package - you could do it like:

sed -nX '/^(([^,]*,){2}c.*)&(.*,)!$/p'

Of course, if the latter case is true, you probably have a similar grep (as can be compiled as a ksh93 builtin, incidentally) and so you should probably do instead:

grep -xX '(([^,]*,){2}c.*)&(.*,)!'
  • Your sed logic is insufficient: you're just checking that the line does not end with a comma, not whether the 5th field is not empty. You'll miss a line like a,b,c,d,e, – glenn jackman Jun 1 '15 at 17:04
  • @glennjackman - Not at all. The description of the file is: Each line in a comma-separated file has 5 fields. Admittedly if that were not the case an additional test like 's/,//5;t' might be called for. – mikeserv Jun 1 '15 at 17:08
2

With awk:

awk -F, '$3 == "c" && $5""' file

In awk, 0 and "" are two false values in boolean context. So if you do something like $3 == "c" && $5, you will miss lines which the fifth field is 0. $5"" force awk coerce fifth field to string, string "0" will be evaluated to true.

1

This is not as short as some answers, but it is the only answer that programmatically says exactly what is asked:

awk '$3 == "c" && $5 != ""' FS=,
0

With perl you could do something like:

perl -F, -nlae 'print if $F[2] eq "c" and $F[4] ne ""'

The -a option splits the lines by the delimiter specified by the -F option and you can afterwards simply check the fields in the @F array.

0

Using python:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        fields = line.rstrip().split(',')
        if fields[2] == 'c' and fields[4]:
            print line.rstrip()

Here we have taken the fields of each line splitted on comma (,) into a list (fields) and then we have checked the conditions on the required fields.

  • I would assign the rstrip() to a new variable and the output from split as well and re-use that for as more readable and faster solution – Anthon May 31 '15 at 5:06
  • @Anthon yeah, you are right..answer edited.. – heemayl May 31 '15 at 13:15

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.