Change directory error

bash ~/match.sh runs fine.

#!/bin/bash
	printf "Enter ID  : "; read id
	printf "What panel: "; read panel
		cd 'C:\Users\cmccabe\Desktop\annovar'
			[ -z "$id" ] && break
			[ "$id" = "end" ] && break
		OMR=Output_Mutation_Report
			perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf 

I am trying to combine shells: bash ~/newbatch.sh

#!/bin/bash
	    printf "What is the id of the patient to be matched  : "; read id
	    printf "What panel: "; read panel
		case "$id" in
		cd 'C:\Users\cmccabe\Desktop\annovar'
	    	    OMR=Output_Mutation_Report
			$( perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf )
		;;
show_menu=true
	menu=( [yY] [nN] )
	func_show() { # "MESSAGE STRING"
	# Prints passed argument
	# Returns nothing
		printf '\n\t%s\n\n' "$1"
	}
#
#	Display & Action
#
	clear
	while $show_menu
	do	printf '#----------------------#\n%s\n' "Are there additonal patients to be matched"
		select entry in "${menu[@]}" Back
		do	case "$entry" in
			Back)		show_menu=false
					;;
			[yY])	$( perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf ) (index id 0) :: $entry
					;;
			[nN])	func_show "printf "Does the file need to be converted  : " ; read id :: ${menu[${#menu[@]}-1]}"
			while true
do
        printf "Enter ID  : " ; read id
		cd 'C:\Users\cmccabe\Desktop\annovar'
        [ -z "$id" ] && break
        [ "$id" = "end" ] && break
        $( perl convert2annovar.pl -includeinfo -format vcf4old ${id}_matched.vcf > ${id}_matched.avinput )
done
					;;
			*)		
			esac
			break
		done
	done 

I am sure the code needs work, but why does it throw an error in the underlined part when it was fine before? Thanks :).

 bash ~/newbatch.sh
What is the id of the patient to be matched  : H62947
What panel: Epilepsy70
/home/cmccabe/newbatch.sh: line 5: syntax error near unexpected token `'C:\Users\cmccabe\Desktop\annovar''
/home/cmccabe/newbatch.sh: line 5: ` cd 'C:\Users\cmccabe\Desktop\annovar''

It wasn't fine before .. you changed it.

2nd version added this:

case "$id" in

turning the underlined portion into part of a case statement - and it's the wrong syntax for a case statement.

What are you trying to do?

How about reading through all the related threads of yours to this very same topic/script!

  1. Combine shell files
  2. Change directory shell
  3. Combine shell files
  4. 2 shells in one file

The way you act, you deny any (already) given answer to you, to anyone who is reading the current thread.
Please show some effort and actualy change what you already have been told to, as in, adapt/apply some of the input you were given already.

Cheers

1 Like

Your code is relatively hard to read, I had real difficulties to decipher the program flow.
I wrote a script which utilizes functions for better understanding.

It assumes following program flow and to me it seems to make more sense than
match -> additional -> additional -> convert (repeated manual input of ids)

menu -> match -> convert? -> NO -> additional? -> NO -> menu
        ^               |          |         |
        |               +--> YES --+         +--> YES +
        |                                             |
        +---------------------------------------------+

Feel free to comment out the "DEBUG INFO" lines if all works as expected; I put them there to see if the variables still contained the values provided in the match function.

Hope this helps.

#!/bin/bash

menu() {
    clear
    printf "\n MENU \n
    ==================================\n\n
    \t 1  Match patient\n
    \t 2  Exit\n\n
    ==================================\n\n"

    printf "\t Your choice: "; read menu_choice

    case "$menu_choice" in
        1) match ;;
        2) printf "\n Bye! \n\n"; exit ;;
        *) printf "\n Invalid choice."; sleep 2; menu ;;
    esac
}


match() {
    printf "\n\n"
    printf "DEBUG INFO: VALUE OF \$id: %s, VALUE OF \$panel: %s\n" $id $panel
    printf "What is the id of the patient to be matched  : "; read id
    printf "What panel: "; read panel

    [ -z "$id" ] && printf "\n No ID supplied. Leaving match function." && sleep 2 && menu
    [ "$id" = "end" ] && printf "\n Leaving match function." && sleep 2 && menu

    cd 'C:\Users\cmccabe\Desktop\annovar'
    OMR=Output_Mutation_Report
    $( perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf )
    convert
}

convert() {
    printf "\n\n"
    printf "DEBUG INFO: VALUE OF \$id: %s, VALUE OF \$panel: %s\n" $id $panel
    printf "Does the file need to be converted? Y/N "; read convert_choice
    
    case "$convert_choice" in
        [yY]) $( perl convert2annovar.pl -includeinfo -format vcf4old ${id}_matched.vcf > ${id}_matched.avinput )
        additional ;;
        [nN]) additional ;;  
        *) convert ;;
    esac
}

additional() {
    printf "\n\n"
    printf "Are there additonal patients to be matched?  Y/N "; read match_choice

    case "$match_choice" in
        [yY]) id=""; panel=""; match ;;
        [nN]) id=""; panel=""; menu ;;  
        *) additional ;;
    esac
}

# actual start of this program
menu # run menu function

Thank you all :)... I am a scientist learning awk so I don't mean to disregard any advice, I truly appreciate it.

Junior-Helper your code works great and is much easier to read and follow the flow. How do you do things like:

 match -> additional -> additional -> convert (repeated manual input of ids) 
menu -> match -> convert? -> NO -> additional? -> NO -> menu
        ^               |          |         |
        |               +--> YES --+         +--> YES +
        |                                             |
        +---------------------------------------------+ 

and use a collapse function for all things related to convert in line 36 or additional in line 49. I use notepad++ on a windows machine. Thank you all again :).

I'm a little bit confused. You say you're learning awk , but there is no awk code in this thread.

Drawing ASCII art may be easier in vi than in notepad++ , but you shouldn't have any problem even in notepad++ as long as you choose a fixed width font (e.g., courier).

Note that there is one problem with the code that junior-helper provided: None of the functions ever return! Instead of returning, each of the functions recursively calls one of the other functions. Every time the script processes another patient, panel, or bad response, it increases the size of the shell's stack. As the stack grows, the shell will slow down until (if enough patients and panels are entered before the user exits the script), it will run into a stack memory allocation limit and die. The following alternative script with a flowchart more like:

			    /\		       /\
			   /  \<-----NO-------/  \<---------------+
			  /    \	     /    \	     +----|----+
 +-------+   +------+	 /  new \	    / new  \	     | process |
 | start |-->| menu |-->< patient>--YES--->< panel  >--YES-->} patient ]
 +-------+   +------+	 \   ?  /	    \  ?   /	     | & panel |
			  \    /    +------+ \    /	     +---------+
       +-------------------\  /-NO->| exit |  \  /-------------------+
       |		    \/      +------+   \/		     |
       |		    ^			^		     |
       |		    |			|		     |
       +--Invalid response--+		    	+--Invalid response--+

uses a couple of loops (instead of recursion) to avoid the continually growing stack issue:

#!/bin/bash

# Main menu...
menu() {
	# Loop reading patient IDs; exit on zero or EOF.
	while [ 1 ]
	do	clear
		printf '\n\nEEnter patient ID (0 to exit): '
		if ! read id || [ "$id" = 0 ]
		then	break
		fi
		if [ "$id" = "" ] || [ "$id" != "${id#*[^0-9]}" ]
		then	printf '\nPatiend ID must be numeric; try again.\n'
			sleep 5
			continue
		fi
		process_panels
	done
        printf "\nBye!\n"
	exit
}

# Proess panels for the current patient ID
process_panels() {
	# Loop reading panels to process for current patient ID ($id)...
	while [ 1 ]
	do	printf "\nEnter panel number for patient ID $id (0 when done): "
		if ! read panel || [ "$panel" = 0 ]
		then	return
		fi
		if [ "$panel" = "" ] || [ "$panel" != "${panel#*[^0-9]}" ]
		then	printf '\nPanel number must be numeric; try again\n'
			continue
		fi

		# Process this panel for this patient...
		printf "DEBUG INFO: Processing patient ID $id, panel $panel\n"
		$(perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp
			s/\cM|\cJ//g
			$p=join("\t",(split/\t/)[4,5])
			($p,$_)} <>
			$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}}
			/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next
			$p=$F[0]."\t".$1
			exists $m{$p} and print join("\t",$_,$m{$p})' \
			${id}_${panel}_${OMR}.txt \
			< ${id}_${panel}_${OMR}_Filtered.vcf \
			> ${id}_matched.vcf)
		printf "\nConvert patient ID $id, panel $panel file (Y/N)?: "
		read convert_choice
		case "$convert_choice" in
		([yY])	printf "Converting patient ID $id, panel $panel file.\n"
			$ perl convert2annovar.pl -includeinfo \
				-format vcf4old ${id}_matched.vcf \
				> ${id}_matched.avinput)
		esac
	done
}

# Initialize location and variables...
cd 'C:\Users\cmccabe\Desktop\annovar'
OMR=Output_Mutation_Report

# Loop through user supplied patient IDs and loop though panels for each
# patient...
menu
1 Like

cmccabe,
If I understand correctly, the answer to your first question regarding the ASCII flowchart is "I did it manually in gedit (https://wiki.gnome.org/Apps/Gedit\) with a monospaced font (https://en.wikipedia.org/wiki/Monospaced_font\) conveniently called Monospace".

I don't understand what you mean with "collapse function". Seems to be a notepad++ question :confused:
Sorry, I have neither notepad++ nor a Windows machine.

Don,
thank you for the hint.
Is it possible to make the functions "return", without major changes?
I admit I misused the functions as goto replacement :rolleyes:

I guess I have a lot to learn :).... thank you

I will do some tutorials on the different programs and hopefully that will be a good start.

If I may chime in an opinion.
You have been trying for sometime to make a Bash wrapper for some Perl code. You mentioned Awk as well. I have the feeling you have been trying to absorb as much you could of any and all of these scripting means.

Why do you not concentrate a bit on just Perl and make that concept you have been trying a robust one? Perl would be a more homogenous and robust solution; and creating a menu is not that difficult on it. The end result of learning Perl is that it would benefit far more in your scientist projects that the shell or even Awk could do.

1 Like

Your code assumes that each patient will only have one panel (so you have your user enter a patient ID and a panel number together). My code assumes that a single patient will frequently go through multiple panels (so I have my user enter a patient ID and then enter panel numbers in a loop for that patient; and when all panels have been processed for that patient, loop through other patients).

To get rid of the recursion in your code, remove the additional function and change every call to additional into a return statement. You will then either need to insert a loop into your menu function or at the end of your script, change:

menu

to:

while [ 1 ]
do  menu
done

And then, finally, remove the call to menu in menu and change calls to menu in match to return statements.

2 Likes

That is a great suggestion Aia. I have been trying to make a bash to make it easier for users to use without needing much scripting, ideally none but as little as needed. Anyway, below is a start (I hope):

 
#!/usr/bin/perl

use strict;
use warnings;
use Switch;

my $input = '';

while ($input ne '7')
{
    clear_screen();

    print "type 1 for mutation match\n".
          "type 2 for annovar conversion\n". 
          "type 3 for individual or sanger annotation\n". 
          "type 4 for batch or sanger annotation\n". 
          "type 5 for individual noonan syndrome anotation\n".
		  "type 6 for batch noonan syndrome annotation\n".
          "type 7 to end\n";
		  
		   print "Enter your choice: ";
    $input = <STDIN>;
    chomp($input);

    switch ($input)
    {
        case '1'
        {
            $input = ''; 

I am not sure if that is correct or how to call a command based on the menu selection. For example, if 1 is inputed, then something like this needs to result.

 
printf "Enter ID  : "; read id
	printf "What panel: "; read panel
		cd 'C:\Users\cmccabe\Desktop\annovar'
			[ -z "$id" ] && break
			OMR=Output_Mutation_Report
	perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf 

Thank you all for the great suggestions and ideas, I have a lot to learn :).

@cmccabe

If you are serious about it, you are going to have to learn and figure out what this line does first and how to converted from a command line invocation to a Perl code script. Calling Perl inside Perl would be a bit silly.

perl -aF/\\t/ -lne 'BEGIN{%m=map{chomp;s/\cM|\cJ//g;$p=join("\t",(split/\t/)[4,5]);($p,$_)} <>;$m{"#CHROM\tINFO"}=$m{"Chr\tSegment Position"}};/SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;$p=$F[0]."\t".$1;exists $m{$p} and print join("\t",$_,$m{$p})' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf

Since it is very ugly and hard to read, I separated them in sections to facilitate understanding for you.

perl -aF/\\t/ -lne '

  BEGIN{
    %m = map{ chomp;
              s/\cM|\cJ//g;
              $p = join ("\t",(split/\t/)[4,5]);
              ($p, $_)
            } <>;
    $m{"#CHROM\tINFO"} = $m{"Chr\tSegment Position"}
  };

  /SEGPOS=(\d+)/ || /\t(INFO)\t/ or next;
  $p=$F[0]."\t".$1;
  exists $m{$p} and print join("\t",$_,$m{$p})

' ${id}_${panel}_${OMR}.txt < ${id}_${panel}_${OMR}_Filtered.vcf > ${id}_matched.vcf

Also, you'll need to figure out how to deal with all those shell variables, like ${id}, ${panel}, etc. Perl would not inherit those from the shell automatically.

Once, you do that, you might be ready for a menu.
There are many ways of doing it, depending on the design. Here's just a guide:

#!/usr/bin/perl

use strict;
use warnings;

sub run {
    print "I am running...\n";
}

sub walk {
    print "I am walking...\n";
}

sub dance {
    print "I am dancing...\n";
}

sub stop {
    print "See you!\n";
    exit;
}


sub menu {
    my $items  = shift;
    my $number = 1;

    print "\nWhat would you like me to do:\n";
    for my $item ( @{$items} ) {
        printf "%d: %s\n", $number++, $item->{'message'};
    }
    print "\nEnter option number: ";

    while (my $input = <STDIN>) {
        chomp $input;
        if ($input =~ m/\d+/
                and $input <= @{$items}
                and $input > 0) {
            return &{$items->[$input -1]->{$input}};
        }

        print "\nInvalid option, please try again: ";
    }
}

my @choice = (
    { 'message' =>     'running', '1' =>   \&run, },
    { 'message' =>     'dancing', '2' => \&dance, },
    { 'message' =>     'walking', '3' =>  \&walk, },
    { 'message' => 'end program', '4' =>  \&stop, },
);

while (1) {
    menu( \@choice );
}

There are no substitute for practicing and practicing some more.

After practice for some time, you could take a look at CPAN and search for menus. There are some modules to build some menus, like Term::Menus

Hi.

Yes, practice. It would probably be useful to look over some books. The page at Perl - Programming - Books & Videos�-�O'Reilly Media lists an abundance of books.

An older list for scientific computing is available at recommendations on scientific computing with Perl

If you write a lot of perl, look into the utility perltidy, it will save you many times over. Always look in your repositories for perl codes, there are a ton of libraries available. You might find some things at The Comprehensive Perl Archive Network - www.cpan.org that are useful. I never install anything in my system unless I use the package manager (apt-get, yum zypper, etc), but rather I put codes in ~/bin , and ~/executable .

We used O'Reilly books in the perl classes I taught. You are out of the beginner state when you have written 100 non-trivial programs ( drl's rule :slight_smile: ) I'd recommend Learning, Intermediate, and Mastering for a full course. You didn't say what your field is, but if it's the life sciences, then the Bioinformatics might be useful.

A few books from publisher Manning are also useful, Data Munging, and OO perl.

However, before you start on this, you may wish to compare perl and Python, say from The Fall Of Perl, The Web's Most Promising Language

Best wishes ... cheers, drl

1 Like

Thank you :). My field is life sciences, specifically Molecular Diagnostics and genetics. Bioinformatics is a necessary and important skill to have and develop.