2

I'm looking to find out any farmer who produces bananas and his address from a database.

My data looks something like this:

- farmer1 address1 apple1,banana-green,orange-5  
- farmer2 address2 orange-unriped6,apple-red,banana-canarvon,peach-sweet 
- farmer3 address3 peach-blacklisted,orange-ok,lime-unriped 
- farmer4 address4 banana-humungous,orange-meh,watermelon-amazing,vegetables-fresh

I've tried grep, cut and awk but I'm unable to print out just the key details into a text file which I hope to look something like:

- farmer1 address1 banana-green
- farmer2 address2 banana-canarvon
- farmer4 address4 banana-humongous

Can anyone help please?


So after using Cas' script (thanks Cas!), i'm able to extract the information i require - which is perfect! However, i have a text file containing a list of information i require and i hope to repeat this process for the whole list (about 400 items). I've tried modifying the script to cope with a list but i'm doing something wrong. It seems to "function" but nothing is printing.

#! /usr/bin/perl -a -n

open( GENEFILE, "ActinGenesENST.txt") or die "$!";
open( VARFILE, "Actin.ENSTvars.txt") or die "$!";
open( OUTPUTFILE, "test.txt") or die "!";
print "Extracting Genes\n";
while (<GENEFILE>) {
        if (/VARFILE/) {
        @produce=grep(/VARFILE/,split(/,/,$F[9])) ;
        print OUTPUTFILE join("\t",@F[0 .. 8],join(",",@produce)),"\n";
        }
}
  • My "farmer's list" is in VARFILE.
  • My "fruits list" is in GENEFILE.
  • I wish to print out returned values in TEST.TXT.
  • if you could use tabs rather than spaces as the separator between columns, then it wouldn't be a "random column" that contained the produce list, it would always be the third column. and that third column would consist of one or more comma-separated fields. – cas Oct 1 '15 at 6:55
  • yeah, the data is separated with a tab rather than a space. I tried extracting the word banana* by the following command: cut -d "," -f 3 | grep banana > details.txt but the results have always included the entire list rather than just bananas*. – royston Oct 1 '15 at 7:02
  • Hi @don_crissti, i'm not sure whether each farmer only produces one bananas. I'm hoping to extract as much details about each bananas (if multiple bananas exists) as possible. I've got one script that works, now i need to get the logic right for the next bit to also work. I'm really struggling with programming logic :/ – royston Oct 2 '15 at 0:15
  • see my second script, it should be easy to adapt for your your real non-fruit data. – cas Oct 2 '15 at 0:47
  • wow. Thanks cas. I really appreciate your help here. I've been trying for the last 2 hours manipulating it to what i can find in google and i'm pretty sure a visit to the local wig shop is due. After seeing what you post, i'm proud i tried cos i'm never able to write that script anytime soon. Cheers mate. – royston Oct 2 '15 at 1:29
1

I put your sample data into a file called farmer.txt, and ran the following perl script:

#! /usr/bin/perl -a -n

if (/banana/) {
  @produce=grep(/banana/,split(/,/,$F[2])) ;
  print join("\t",@F[0 .. 1],join(",",@produce)),"\n";
}

which produced this output:

$ ./bananas.pl farmer.txt
farmer1 address1    banana-green
farmer2 address2    banana-canarvon
farmer4 address4    banana-humungous

For every line in the input that contains "banana", it splits the third field $F[2] by commas into a list called @produce, and uses perl's grep() function to keep only elements containing the word banana.

Then it prints them out in the same format as the input.

Note that if a farmer produces more than one kind of banana then this script WILL display them all.

Here's a version of the script that can print multiple "fruits" (contained in 'fruitlist.txt'):

#! /usr/bin/perl 

use strict;

my $fruitlist='fruitlist.txt';

open(FRUITS,"<",$fruitlist) || die "couldn't open $fruitlist: $!\n";
while (<FRUITS>) {
    chomp ;
    my $fruit = $_;
    print "$fruit\n---\n";

    foreach my $file (@ARGV) {
      open(FILE,"<",$file) || die "couldn't open $file: $!\n";

      while(<FILE>) {
        my @F=split(/\t/);

        if (/$fruit/) {
          my @produce=grep(/$fruit/,split(/,/,$F[2])) ;
          print join("\t",@F[0 .. 1],join(",",@produce)),"\n";
        }
      }
      close(FILE);
      print "\n";
    }
};
close(FRUITS);

I've dropped the perl -a (awk-like) mode and made it explicitly open files and split the contents into the @F field array because it needs to re-open the input file(s) (e.g. farmer.txt) multiple times, once for each entry in fruitlist.txt.

If fruitlist.txt contains two lines (banana and apple), the script will produce the following output:

$ ./multifruit.pl farmer.txt 
banana
---
farmer1 address1    banana-green
farmer2 address2    banana-canarvon
farmer4 address4    banana-humungous

apple
---
farmer1 address1    apple1
farmer2 address2    apple-red
  • BTW, the field separators in the output ARE tabs, they just got converted to spaces when i cut-and-pasted them from my terminal. – cas Oct 1 '15 at 8:10
  • hey cas! thanks for the script! I tried running the perl script but changed it to fit my data and it came back with this error. I'm utterly useless in perl. Trying to learn it as i go. So i apologise in advance for anything presumably newbie. – royston Oct 1 '15 at 12:41
  • This is the modifications i made: perl -a -n -e 'if (/ENST00000366684/) { @produce=grep(/ENST00000366684/,split(/,/,$F[9])) ; print join("\t",$F[0],$F[1],$F[2],$F[3],$F[4],$F[5],$F[6],$F[7],$F[8],join(",",@produce)),"\n"; }' Actin.ENSTvars.txt – royston Oct 1 '15 at 12:47
  • and it threw me this error: Bareword found where operator expected at /home/ubuntu/scripts/bananas.pl line 3, near "print join("\t",$F[0],$F[1],$F[2],$F[3],$F[4],$F[5],$F[6],$F[7],$F[8],join(",",@produce)),"\n"; }' Actin" (Might be a runaway multi-line '' string starting on line 1) (Do you need to predeclare print?) syntax error at /home/ubuntu/scripts/bananas.pl line 1, near "n -e " – royston Oct 1 '15 at 12:48
  • i'm not sure what you've done there. your version looks OK to me. try turning it into a standalone script (rather than a one-liner) as i've just done to mine above. I've also modified it to use an array slice @F[0 .. 1] instead of explicitly list $F[0], $F[1] which would be more convenient for your @F[0 .. 8] – cas Oct 1 '15 at 23:08
0

Using the commands you posted (sorry I changed cut for sed) I got the next solution:

cat your_file|sed 's/ /,/g'|awk -F, '{for (i=1;i<=NF;i++) {if (index(tolower($i),"banana")) {print $1,$2,$i}}}'

First I changed spaces to , to be able to have all the fields separated with the same field-separator (awk command is easier this way). After that awk does a good job extracting your bananas. I assumed there could only be one banana per farmer but you can easily modify the awk to your needs.

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.