I am having trouble modifying a .sh that allows the user to run different command based of an input. So based on the user input of Y or N a different command is run. Thank you :).
#!/bin/bash
while true
do
printf "Is this a batch : " ; read id
[ -z "$id" ] && break
If "$id" = Y, Then
[ "$id" = "end" ] && break
perl -ne 'chomp; system ("perl table_annovar.pl $_ humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo")' < file.txt
Else
If "$id" = N, Then
printf "Enter ID : " ; read id
[ -z "$id" ] && break
[ "$id" = "end" ] && break
perl table_annovar.pl ${id}_matched.avinput humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo
done
You ought to pay attention to the casing and the proper syntax of the bash shell.
If is not the same that if
Then is not the same that then
Else is not the same that else
Case matters
If "$id" = Y, Then
[ "$id" = "end" ] && break
That's not proper syntax for an if condition in bash
The correct syntax could be: if [ "$id" = Y ]; then
Further more, if the variable $id contains the char Y, how can ever contain the string "end"? Think about that one.
I going to pretend I did not see any of the perl lines.
This particular error means "Stop editing your scripts in Microsoft Notepad". Editing it in a Windows editor has filled them with carriage returns. To repair it:
tr -d '\r' < windowstext > unixtext
Why have you put absolutely everything in the case statement? Most of those statements will never be executed, since it jumps from ;; to esac. Not to mention, you can check for "end" in the same case statement. Try this:
printf "Is this a batch :"
while read id
do
case "$id" in
[yY]) echo perl -ne 'chomp; system ("perl table_annovar.pl $_ humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo")' < file.txt
;;
[nN]) # code for X
printf "Enter ID : " ; read id
[ -z "$id" ] && break
[ "$id" = "end" ] && break
echo perl table_annovar.pl ${id}_matched.avinput humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo
;;
end) break ;;
*) ;; # Unknown option, do nothing
esac
printf "Is this a batch :"
done
It's also quite interesting how here, you have a shell script, which calls perl... which calls system (which is another shell!) -- which calls perl again! You could maybe remove two or three levels of code there with no change.
If you want to specify that the script is to be run by bash when you don't specify a shell to run your script on the command line, you can't have a space before the #!/bin/bash on the 1st line in your script!
If you get into the habit of indenting code in do, then, else, and selections in cases; mistakes like your missing done would be obvious to you.
Yes, you, too, deserve beautified code: maintainable and more error free!
I have seen people adding comments in SQL 'BEGIN -- {' and 'END --}' so they could use vi's % operator to check balance. Shell do and done, then and fi, case and esac, etc. could use that trick for big entries.
Understood. If system() is the very last thing a Perl program does, you might try exec() instead, for some time and resource savings -- perl will replace itself, effectively quitting early, instead of creating a brand new process, and the program which launched it will end up waiting for the new shell.
You could also put exec inside the exec() block informing the shell to do the same thing for further savings -- the process gets replaced twice, the program which launches it ends up just waiting for perl, not shell waiting for perl waiting for shell waiting for perl. The amount of time that saves can be surprising.
I suggested to replace system() with exec(), not wrap it in yet another block.
And my suggestion wasn't entirely serious. The point was to illustrate how many completely unnecessary processes you are running and how much extra complexity to use something that was supposed to be simple. A better solution would be to strip out most of that code and just write it in shell in the first place.
#!/bin/bash
while true
do
printf "Is this a batch :"
case "$id" in
[yY]) echo "perl -ne 'chomp; system ("perl table_annovar.pl $_ humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo")' < file.txt
;;
[nN]) # code for X
printf "Enter ID : " ; read id # This has to be outside the case
[ -z "$id" ] && break # This is not needed, $id will never contain a zero length
[ "$id" = "end" ] && break # This is not needed. $id will never contain "end", here
echo ("perl table_annovar.pl ${id}_matched.avinput humandb/ -buildver hg19 -protocol refGene,popfreq_all,common,clinvar,clinvarsubmit,clinvarreference -operation g,f,f,f,f,f -otherinfo
;;
end) break ;;
*) ;; # Unknown option, do nothing
esac
printf "Is this a batch :"
done
The echo has to go. The red `"' do not have a matching closing on them. They need to go. The rest is explained in the comments.