Error with Term::ReadKey - perl

I’m trying to run this script to check genotyped data for imputation with HRC or 1000G using an imputation server, it can be found here. It is perl-based. It has these packages/libraries it is (trying) to load.
use strict;
use warnings;
use File::Basename;
use Getopt::Long;
use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
use Term::ReadKey qw/ GetTerminalSize /;
However, it throws an error Unable to get Terminal Size. The TIOCGWINSZ ioctl didn't work. The COLUMNS and LINES environment variables didn't work. The resize program didn't work. at /usr/lib64/perl5/vendor_perl/Term/ReadKey.pm line 362.
How do I solve this?

Ah. So the question is sort of solved. It turns out the script in particular is expecting to be run in a terminal, which stays open. That is to say: it is not expecting to be run in a submission-system, which is what I was doing. In fact, I need to run it in a submission-system, because the computer cluster doesn't allow for big data to be run in a terminal, and because the data is just to big to keep waiting for the program to finish. Submitting it to a compute node with more power makes more sense.
The developer of the script, the HRC or 1000G Imputation preparation and checking tool, has kindly provided a non-terminal-requiring script. He will put it online, and/or provide it via email.
solved

Related

unable to send shift-end with Win32::GuiTest

I would need to automate some keyboard entries inside my perl script. For this, I use Win32::GuiTest module.
This works fine for all entries I need except for shift-end.
Here's what I send
Win32::GuiTest::SendKeys("+{END}");
but it seems that it only takes the {END}.
The weird thing is that
Win32::GuiTest::SendKeys("+(some text)");
works fine and sends SOME TEXT
In fact, I am unable to do +{} commands, it always take only the key inside the {}
On the other hand, commands with ^ (ctrl) or % (alt) work fine for example Win32::GuiTest::SendKeys("%{F4}") closes the window
does anybody would know why?
Thanks :)
Late answer, anyway, maybe it is of help to somebody...
Shift{foo} commands like Shift{End} need to be performed with low-level keybd_event via the SendRawKey wrapper. So this is what you are looking for:
SendRawKey(VK_LSHIFT, KEYEVENTF_EXTENDEDKEY);
SendKeys('{END}');
SendRawKey(VK_RSHIFT, KEYEVENTF_KEYUP);
SendRawKey(VK_LSHIFT, KEYEVENTF_KEYUP);
Full sample (copies a complete line into the clipboard):
use warnings;
use strict;
use Win32::Clipboard;
use Win32::GuiTest qw (:ALL); # Win32-GuiTest-1.63 used
print "place cursor now...\n"; sleep(5); print get_line();
sub get_line {
Win32::Clipboard()->Empty();
SendKeys('{HOME}');
SendRawKey(VK_LSHIFT, KEYEVENTF_EXTENDEDKEY);
SendKeys('{END}');
SendRawKey(VK_RSHIFT, KEYEVENTF_KEYUP);
SendRawKey(VK_LSHIFT, KEYEVENTF_KEYUP);
SendKeys('^c');
return Win32::Clipboard()->GetText();
}

perl script to read an excel file using cpan modules

I am writing a perl script to read data from an excel file. The script is being written in an unix environment and run on the server, whereas the excel file is available on my Desktop in Windows.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Spreadsheet::Read;
my $workbook = ReadData ("C:/Users/tej/Desktop/Work.xlsx");
say $workbook->[1]{A1};
The output gives out a warning saying
Use of uninitialized value in say at..... line 10
And there is no other output being printed. I just wrote a sample code to read the A1 cell value from sheet 1. Later, I need to write a logic to read particular values. For right now, need to fix the error to read and print the excel cell values. Appreciate any help. :)
I fixed the issue. It was about file was not being accessed. I used samba to Map unix disk to Windows Network Drive. But now, I get a different error which says : Parser for XLSX is not installed at.. Can someone help me to resolve it.

How can I "use lib" the appropriate directory depending on installation location?

I have an object-oriented web-app that is installed in multiple locations on my server. Once for "live", once for "beta", etc. Being object-oriented, it consists of many perl modules. In the main module, I must "use lib" the appropriate directory for all of the custom perl modules for that instance of the app.
This is no big deal, I have a BEGIN block that checks the location of the main program and sets the library directory appropriately. However I also have a lot of utility, command line programs that need to do the same thing. I don't want to cut and paste this code everywhere.
What is the best way to share this code snippet amongst the various programs that need it?
I can't "use" it because the libary path isn't set up yet. Maybe "do" or "require" would the be the right answer, but both of those will search #INC, which is inappropriate.
Maybe something like eval `cat GetLib.pl`; would be appropriate but it seems kind of clunky and fragile.
Here is the BEGIN block that I currently use:
BEGIN {
use FindBin qw ($Bin);
require lib;
if ($Bin =~ /^\/home\/w\/myapp_live/) {
lib->import('/home/w/myapp_live/lib');
print STDERR "live site\n";
}
if ($Bin =~ /^\/home\/w\/myapp_beta/) {
lib->import('/home/w/myapp_beta/lib');
print STDERR "beta site\n";
}
if ($Bin =~ /^\/home\/w\/myapp_test/) {
lib->import('/home/w/myapp_test/lib');
print STDERR "testing site\n";
}
}
Thank you!
FindBin::libs is excellent for that. I've used it for a while in a large system with no problems at all.
The default invocation looks like it'll work for you, simply:
use FindBin::libs;
This will search for all the ./lib dirs in all the parent directories of the current file's dir and use lib them. So, for example, if your script lives in /home/w/myapp_live/scripts/defurblise_widgets.pl (and use()es FindBin::libs), it will look for:
/home/w/myapp_live/scripts/lib
/home/w/myapp_live/lib
/home/w/lib
/home/lib
/lib # (presumably!)
Any that it finds with be added to you #INC with use lib.
But, if that's not quite what you need, it's a very flexible module. I'd be surprised if you can't find a way to make it do what you want.
If you're running a program from the command line, don't programmatically set the lib: just pass it in as an argument, e.g.: perl -I/location/of/my/lib myprog.pl.
For your web app, why don't you make your library relative to the location of the script itself? Then just install it on each machine where the libraries live.
use FindBin;
use File::Spec::Functions;
use Cwd qw(abs_path getcwd);
BEGIN {
my $curdir = getcwd;
my $selfdir = $FindBin::Bin;
my $libdir = abs_path(catdir($selfdir, 'lib'));
chdir $libdir or die "can't chdir to $libdir: $#";
use lib $libdir;
}
Of course, the easiest option of all is to not use different lib directories. Why can't you be consistent across all your environments?
Edit. Re your comment "The reason I have to use different lib directories is because the code running in the live site is different than the code running on the beta site... that's the point of having a beta site." -- why don't you handle this at the level of the installer, rather than making the code itself have to know whether it's live vs. beta? e.g. store your code in different directories in your source tree as you do now, but only install the relevant code to each box. After all, that's exactly what a good revision control system would do for you -- you only check out one branch at a time, and you should only be installing one version of code at a time (as brian d foy alluded to).
I use the following in many of my scripts:
use strict;
use warnings;
use 5.008;
use FindBin;
use lib $FindBin::Bin;
That last line could be modified as such:
use FindBin;
use lib "$FindBin::Bin/lib";
The different environments could have different settings for the environment variable $PERL5LIB.
The code you've shown looks reasonable. You could install one copy of that code into a system-wide location, and then the code to invoke it would boil down to
require '/path/to/findlib.pl';
findlib->import;
The form of require that takes a filename doesn't search #INC.
As an alternative if you wanted to change lots of things around you could look into deploying the app in a way that would be more friendly to local::lib usage.

Why doesn't "use lib" take effect in this way?

In my app, I put all the modules in one directory , let's just call it libx.
Since it's up to the user to choose where to deploy the app, I don't want to hardcode the lib path.
So at the beginning of myapp.pl, I wrote the following lines of code.
#! /usr/bin/perl -w
use strict;
my $curr_dir = $0;
my $curr_lib = $curr_dir;
$curr_lib =~ s/myapp\.pl/libx/;
use $curr_lib ;
Instead of getting what I'm expecting, I got compiling errors!
So what's wrong with my code? I don't want to hardcode the lib path when using use lib, how should I do this?
Sorry I forgot to mention that when the app is deployed, myapp.pl and libx are in the same directory.
use happens at compile-time, not run-time, so your variable hasn't been set yet.
You can do:
my $curr_lib;
BEGIN {
$curr_lib = $0;
$curr_lib =~ s/myapp\.pl/libx/;
}
use lib $curr_lib;
or you could:
use FindBin;
use lib "$FindBin::Bin/libx";
I had trouble with this before too. What's happening is that Perl makes two passes over your code: once to compile it, and the second time to run it. In you example, lines 4,5, and 6 don't execute until run time, but use takes effect during compile time.
One possibility is to put it all inside a BEGIN{} block, which will make the code execute at compile time. I've done this, but it's messy/ugly. (BTW, instead of $0, you need to use $ARGV[0] in Perl).
The best way to tell Perl where to pick up libraries is to use the -I flag. You can put it on the #! line, or if you are starting the script from another script, you can start it as
perl -I/your/directory/libx your_script.pl
You can use relative paths, so maybe
perl -I./libx script.pl
would work for you.
use xxx is a compile-time directive, not a run-time instruction. You cannot set it programmatically within the script you are running.
You may need to try require rather than use
If you need use, you need to set your $PERL5LIB environment variable to ensure your modules are correctly located and used, or change your shebang line to read #! /usr/local/perl -w -I/path/to/libx. There are other methods (local::lib etc.), but from your question it seems your control over installation is a bit limited for that sort of approach.

Can I rate a song in iTunes (on a Mac) using Perl?

I've tried searching CPAN. I found Mac::iTunes, but not a way to assign a rating to a particular track.
If you're not excited by Mac::AppleScript, which just takes a big blob of AppleScript text and runs it, you might prefer Mac::AppleScript::Glue, which provides a more object-oriented interface. Here's the equivalent to Iamamac's sample code:
#!/usr/bin/env perl
use Modern::Perl;
use Mac::AppleScript::Glue;
use Data::Dumper;
my $itunes = Mac::AppleScript::Glue::Application->new('iTunes');
# might crash if iTunes isn't playing anything yet
my $track = $itunes->current_track;
# for expository purposes, let's see what we're dealing with
say Dumper \$itunes, \$track;
say $track->rating; # initially undef
$track->set(rating => 100);
say $track->rating; # should print 100
All that module does is build a big blob of AppleScript, run it, and then break it all apart into another AppleScript expression that it can use on your next command. You can see that in the _ref value of the track object when you run the above script. Because al it's doing is pasting and parsing AppleScript, this module won't be any faster than any other AppleScript-based approach, but it does allow you to intersperse other Perl commands within your script, and it keeps your code looking a little more like Perl, for what that's worth.
You can write AppleScript to fully control iTunes, and there is a Perl binding Mac::AppleScript.
EDIT Code Sample:
use Mac::AppleScript qw(RunAppleScript);
RunAppleScript(qq(tell application "iTunes" \n set rating of current track to $r \n end tell));
Have a look at itunes-perl, it seems to be able to rate tracks.