grubent has asked for the wisdom of the Perl Monks concerning the following question:

Hello perlMonks! I am turning to the internet for what I am sure is a very benign issue with my perl script. I am trying to convert a file from one format to the other but continue to get these errors that read this: syntax error at ./impute2chromopainter_ng.pl line 56, near ") {" syntax error at ./impute2chromopainter_ng.pl line 59, near "else" syntax error at ./impute2chromopainter_ng.pl line 64, near "}" Execution of ./impute2chromopainter_ng.pl aborted due to compilation errors. I am not sure how to modify the code in a way that will allow it to run. I did not write this script it was written by authors who designed fineStructure! Please, any guidance or advice would be immensely appreciated! Thank you! The code is below

#!/usr/bin/perl ## CONVERTS PHASED IMPUTE2 OUTPUT TO CHROMOPAINTER-STYLE INPUT FILES sub help { print("CONVERTS PHASED SHAPEIT/IMPUTE2 OUTPUT TO CHROMOPAINTER-STYLE I +NPUT FILES\n"); print("usage: perl impute2chromopainter.pl <options> impute_output_f +ile.haps output_filename_prefix\n"); print("where:\n"); print(" (i) impute_output_file.haps = filename of IMPUTE2 outpu +t file with suffix \".haps\" that contains phased haplotypes\n"); print(" (ii) output_filename_prefix = filename prefix for chrom +opainter input file(s). The suffix \".phase\" is added\n\n"); print("The output, by default, is in CHROMOPAINTER v2 input format.\n" +); print("<options>:\n"); print("-J: Jitter (add 1) snp locations if snps are no +t strictly ascending. Otherwise an error is produced.\n"); print("<further options> NOTE: YOU ONLY NEED THESE OPTIONS FOR BACKW +ARDS COMPATABILITY!\n"); print("-v1: Produce output compatible with CHROMOPAINTE +R v1, i.e. include the line of \"S\" for each SNP. \n"); print("-f: By default, this script produces PHASE-styl +e output, which differs from \n"); print(" ChromoPainter input which requires an additional + first line. This option creates the correct\n"); print(" first line for standard fineSTRUCTURE usage +(i.e. the first line is \"0\", all other lines are appended)\n\n"); print("NOTE: TO USE IN CHROMOPAINTER: You also need a recombination ma +p. Create this with the \"convertrecfile.pl\" or \"makeuniformrecfile +.pl\" scripts provided.\n\n"); print(" !!! WARNING: THIS PROGRAM DOES NOT SUFFICIENTLY CHECK FOR MIS +SPECIFIED FILES. WE ARE NOT ACCOUNTABLE FOR THIS RUNNING INCORRECTLY +!!!\n"); die "\n"; } use feature "switch"; ############################### ## INPUT: $numindsmaxsize=500; ## ONLY READ IN THIS NUMBER OF IMPUTE2 INDS A +T A TIME (TO MINIMIZE RAM REQUIREMENTS -- MAKES PROGRAM RUN A FACTOR +OF (N/$numindsmaxsize) SLOWER THAN IF YOU SET $numindsmaxsize=N, wher +e N is the total number of individuals in your ".haps" IMPUTE2 output + file, but also uses a factor of (N/$numindsmaxsize) less RAM ############################### ## ARGUMENT PROCESSING $v1=0; ## version 1 mode $fsmode=0; ## finestructure mode (i.e. start with an additional line c +ontaining 0) $jitter=0; ## whether we jitter snp locations $Mb = 1000000.0; $IMPUTEinfile=""; $outfilePRE=""; $argon=0; for (my $i = 0; $i < scalar(@ARGV); ++$i){ if(@ARGV[$i] eq "-f"){ $fsmode=1; }elsif(@ARGV[$i] eq "-v1"){ $v1=1; }elsif(@ARGV[$i] eq "-J"){ $jitter=1; }else{ switch($argon) { my $case = 0; {$IMPUTEinfile="$ARGV[$i]";} my $case = 1; {$outfilePRE="$ARGV[$i]";} else { help(); } } $argon++; } } if($outfilePRE eq "" || $argon != 2) {help();} $outfilePRE =~ s/.phase$//; ############################## ## PROGRAM: ## (II) GET NUMBER OF SITES AND INDS: open(IN,"$IMPUTEinfile"); $line=<IN>; @linearray=split(/\s+/,$line); $totalINDS=(@linearray-5)/2; $totalhaps=@linearray-5; $numsplits=int($totalINDS/$numindsmaxsize); if (($numsplits*$numindsmaxsize)<$totalINDS) { $numsplits=$numsplits+1; } $nsites=1; while(<IN>) { $line=$_; $nsites=$nsites+1; } #print "$numsplits $nsitesFULL $totalINDS\n"; ## (III) READ IN IMPUTE2 HAPLOTYPES AND MAKE CHROMOPAINT +ER HAPLOTYPE INPUT FILE: open(OUT,">${outfilePRE}.phase"); if($fsmode==1) { print OUT "0\n"; } for ($a=0; $a < $numsplits; $a+=1) { $startIND=$a*$numindsmaxsize; $endIND=($a+1)*$numindsmaxsize; if ($endIND > $totalINDS) { $endIND=$totalINDS; } ## read in: open(IN,"$IMPUTEinfile"); @rsvec=(); @posvec=(); @genomat=(); $snpcount=0; while(<IN>) { $line=$_; @linearray=split(/\s+/,$line); push(@rsvec,$linearray[1]); # print("BEFORE: SNP location $linearray[2] lup $lastuniquesnp\n"); if(scalar(@posvec)>0 &&($linearray[2] <= $posvec[-1]) && $linearra +y[2]>=0){ if(!$jitter){ die("ERROR: SNPs are not strictly ascending, exiting. Rerun wi +th -J to jitter the SNP locations.\n"); } # print("Duplication found: setting $linearray[2] to $posvec[-1 +]+1\n"); $linearray[2]=$posvec[-1]+1; } # print("AFTER: SNP location $linearray[2] lup $lastuniquesnp\n"); if( $linearray[2] == $posvec[-1] ){ die("Strange error due to jittering?\n"); } push(@posvec,$linearray[2]); # shift(@linearray); # shift(@linearray); # shift(@linearray); # shift(@linearray); # shift(@linearray); for ($i=$startIND; $i < $endIND; $i+=1) { $genomat[(($i-$startIND)*2)][$snpcount]=$linearray[(2*$i)+5]; $genomat[(($i-$startIND)*2+1)][$snpcount]=$linearray[(2*$i+1)+ +5]; } $snpcount=$snpcount+1; } ## print out: if ($a==0) { if($v1){ print OUT "$totalINDS\n"; }else { print OUT "$totalhaps\n"; } print OUT "$nsites\n"; print OUT "P @posvec\n"; if($v1){ for ($j=0; $j < $nsites; $j+=1) { print OUT "S"; } print OUT "\n"; } } for ($i=0; $i < (2*($endIND-$startIND)); $i+=1) { for ($j=0; $j < $nsites; $j+=1) { print OUT "$genomat[$i][$j]"; } print OUT "\n"; } }

Replies are listed 'Best First'.
Re: HELP fix error in fineStructure conversion script
by Paladin (Vicar) on Jul 26, 2019 at 23:17 UTC
    I'm not sure where you got that switch syntax, but it's wrong. Check out perlsyn for the correct syntax (using given/when), although note that it's experimental, and you need to add a line to suppress the warnings as noted in the docs. You can rewrite it with a normal if/elsif/else chain.
Re: HELP fix error in fineStructure conversion script
by AnomalousMonk (Archbishop) on Jul 26, 2019 at 23:53 UTC

    Yeah, the problem starts with the
        switch($argon) { ...
    block opening — but that's not any "switch" syntax I'm familiar with (that
        my $case = 0; { ... }
    stuff is really strange); see Switch Statements in perlsyn. However, I tend to stay away from weird experimental things so I'm not the best authority on this topic. I'd echo Paladin's advice to re-write.


    Give a man a fish:  <%-{-{-{-<

Re: HELP fix error in fineStructure conversion script
by AnomalousMonk (Archbishop) on Jul 27, 2019 at 00:07 UTC
    switch($argon) { my $case = 0; {$IMPUTEinfile="$ARGV[$i]";} my $case = 1; {$outfilePRE="$ARGV[$i]";} else { help(); } }

    As for re-writing, try (untested):

    if ($argon == 0) { $IMPUTEinfile = "$ARGV[$i]"; } elsif ($argon == 1) { $outfilePRE = "$ARGV[$i]"; } else { help(); }
    (But remember that I'm only looking at the "switch" block and guessing; I do not have an understanding of the overall program.)

    Update: Normally I'd advise adding the statements
        use strict;
        use warnings;
    (see strict and warnings) at the very beginning of the script, but in this case I think you'd end up with so much stuff to fix that maybe the best strategy here really is to make changes at random and pray for the best.


    Give a man a fish:  <%-{-{-{-<

Re: HELP fix error in fineStructure conversion script
by AnomalousMonk (Archbishop) on Jul 27, 2019 at 00:42 UTC
    $outfilePRE =~ s/.phase$//;

    One other little cautionary note. In a regex (as in the  s/// quoted above), the  . (dot) is a "metacharacter", a regex operator that, by default, matches any character except a newline (see perlre). I don't understand the purpose of the quoted substitution, but if it's to remove a literal  .phase substring extension from the end of a file name, you may be surprised:

    c:\@Work\Perl\monks>perl -wMstrict -le "my $filename = 'foo.xyphase'; print qq{'$filename'}; ;; $filename =~ s/.phase$//; print qq{'$filename'}; " 'foo.xyphase' 'foo.x'
    To have the regex match a literal period character, escape the dot:
        $outfilePRE =~ s/\.phase$//;

    Good luck with this program.


    Give a man a fish:  <%-{-{-{-<