Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.

by pritesh_ugrankar (Monk)
on Oct 02, 2020 at 02:01 UTC ( [id://11122460]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

I am having a really strange issue.

I am using Strawberry perl version 5.30 (v5.30.3) on Windows Server 2008R2.

There's a perl script I've written (with lots of help from perlmonks), and it runs fine if I execute it from within the directory where it's located like so:

G:\cdr_vnxe>perl cedar_rapids_vnxe_v2.pl G:\cdr_vnxe>

The perl script executes, sends email and the command prompt returns. However, running it by giving the path gives the following error:

G:\>perl cdr_vnxe\cedar_rapids_vnxe_v2.pl Use of uninitialized value $text in substitution (s///) at G:/Strawber +ry/perl/vendor/lib/Win32/ShellQuote.pm line 85. G:\>

I've googled a lot, tried commenting out certain portion of the script that I thought is messing up, but nothing works. Unfortunately the script is way to long. I don't even know which part of my script is causing this. So I've given the whole script here. I'm supposed to provide only a snippet, but in this case I am not even sure which part is causing this. Once again I apologize for giving the whole script here, but I really do not know which part of the script is causing this. I will be ever so thankful if the monks could help.

###################################################################### use strict; use warnings; use Config::Tiny; use IPC::Run3; use Encode qw/decode/; use Email::Stuffer; use Email::Sender::Transport::SMTP (); use Cwd; ###################################################################### my $array_creds = Config::Tiny->new(); $array_creds = Config::Tiny->read('vnxe_config.conf'); my $mailserver = $array_creds->{params}->{smtp_server_name}; my $username = $array_creds->{params}->{username}; my $password = $array_creds->{params}->{passwd}; my $vnxe_ip = $array_creds->{params}->{vnxe_ip}; my $aref_cmd_genhealth = ['uemcli','-d',$vnxe_ip,'-u',$username,'-p',$ +password, '/sys/general','show','-detail']; my $aref_cmd_bat = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $ +password, '/env/bat', 'show', '-detail']; my $aref_cmd_ps = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $p +assword, '/env/ps', 'show', '-detail']; my $aref_cmd_disks = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', + $password, '/env/disk', 'show', '-detail']; my $aref_cmd_pools = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', + $password, '/stor/config/pool', 'show', '-detail']; my $aref_cmd_dpe = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $ +password, '/env/dpe', 'show', '-detail']; my $aref_cmd_ccard = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', + $password, '/env/ccard', 'show', '-detail']; my $aref_cmd_dae = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $ +password, '/env/dae', 'show', '-detail']; my $aref_cmd_iomod = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', + $password, '/env/iomodule', 'show', '-detail']; my $aref_cmd_sp = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $p +assword, '/env/sp', 'show', '-detail']; my $aref_cmd_ssd = ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $ +password, '/env/ssd', 'show', '-detail']; ###################################################################### #Use the run3 from IPC::Run3 so that the output will be captured #in the \my $variable reference.This can be used later when the #output is decoded from UTF 16 and written to a file. #Why is this being done? - Because the uemcli output is in UTF16 #Format and does not render nicely in text files. ###################################################################### #TODO:- See if this can be done in a subroutine for DRY. ###################################################################### run3 $aref_cmd_genhealth, undef, \my $genhealth; run3 $aref_cmd_bat, undef, \my $bat; run3 $aref_cmd_ps, undef, \my $pow_sup; run3 $aref_cmd_disks, undef, \my $disks; run3 $aref_cmd_pools, undef, \my $pools; run3 $aref_cmd_dpe, undef, \my $dpe; run3 $aref_cmd_ccard, undef, \my $ccard; run3 $aref_cmd_dae, undef, \my $dae; run3 $aref_cmd_iomod, undef, \my $iomod; run3 $aref_cmd_sp, undef, \my $sp; run3 $aref_cmd_ssd, undef, \my $ssd; ###################################################################### #This is where the decoding and writing to file or variable starts. ###################################################################### #TODO:- See if this can be done in a subroutine for DRY. ###################################################################### my $genhealthfile = "genhealthfile.txt"; open (my $fh_genhealthfile, '+>', $genhealthfile) or die "Cannot open +file.$!"; my $str_genhealth = decode('UTF-16', $genhealth, Encode::FB_CROAK); print $fh_genhealthfile $str_genhealth; close $fh_genhealthfile; open ($fh_genhealthfile, '<', $genhealthfile) or die "Cannot open file +.$!"; my $array_system; my $array_model; my $array_sn; while (my $line = <$fh_genhealthfile>) { if ($line =~/System.*=\s(.*)/) { $array_system = $1; } if ($line =~/Model.*=\s(.*)/) { $array_model = $1; } if ($line =~/serial.*=\s(.*)/) { $array_sn = $1; } } close $fh_genhealthfile; my $array = "$array_system "."$array_model "."$array_sn "; my $email_subject = $array."Health Check & Capacity"; my $batteries = "batteries.txt"; open (my $fh_batteries, '+>', $batteries) or die "Cannot open file.$!" +; my $str_batt = decode('UTF-16', $bat, Encode::FB_CROAK); print $fh_batteries $str_batt; close $fh_batteries; my $power_supply = "power_supply.txt"; open (my $fh_power_supply, '+>', $power_supply) or die "Cannot open fi +le.$!"; my $str_power_supply = decode('UTF-16', $pow_sup, Encode::FB_CROAK); print $fh_power_supply $str_power_supply; close $fh_power_supply; my $physical_disks = "physical_disks.txt"; open (my $fh_physical_disks, '+>', $physical_disks) or die "Cannot ope +n file.$!"; my $str_phys_disks = decode('utf-16', $disks, Encode::FB_CROAK); print $fh_physical_disks $str_phys_disks; close $fh_physical_disks; my $capacity = "capacity.txt"; open (my $fh_ph_disks, '+>', $capacity) or die "Cannot open file.$!"; my $str_ph_disks = decode('utf-16', $pools, Encode::FB_CROAK); print $fh_ph_disks $str_ph_disks; close $fh_ph_disks; my $used_capacity; { open ($fh_ph_disks, '+<', $capacity) or die "Cannot open file.$!"; local $/ = "\n\n"; while (<$fh_ph_disks>) { next if $_ =~/^(Storage|HTTPS)/; if ($_ !~ /Total space = 0/) { $used_capacity = $_; } } } my $dpe_file = "dpe_file.txt"; open (my $fh_dpe_file, '+>', $dpe_file) or die "Cannot open file.$!"; my $str_dpe = decode('utf-16', $dpe, Encode::FB_CROAK); print $fh_dpe_file $str_dpe; close $fh_dpe_file; my $ccard_file = "ccard_file.txt"; open (my $fh_ccard_file, '+>', $ccard_file) or die "Cannot open file.$ +!"; my $str_ccard = decode('utf-16', $ccard, Encode::FB_CROAK); print $fh_ccard_file $str_ccard; close $fh_ccard_file; my $dae_file = "dae_file.txt"; open (my $fh_dae_file, '+>', $dae_file) or die "Cannot open file.$!"; my $str_dae = decode('utf-16', $dae, Encode::FB_CROAK); print $fh_dae_file $str_dae; close $fh_dae_file; my $iomod_file = "iomod_file.txt"; open (my $fh_iomod_file, '+>', $iomod_file) or die "Cannot open file.$ +!"; my $str_iomod = decode('utf-16', $iomod, Encode::FB_CROAK); print $fh_iomod_file $str_iomod; close $fh_iomod_file; my $sp_file = "sp_file.txt"; open (my $fh_sp_file, '+>', $sp_file) or die "Cannot open file.$!"; my $str_sp = decode('utf-16', $sp, Encode::FB_CROAK); print $fh_sp_file $str_sp; close $fh_sp_file; my $ssd_file = "ssd_file.txt"; open (my $fh_ssd_file, '+>', $ssd_file) or die "Cannot open file.$!"; my $str_ssd = decode('utf-16', $ssd, Encode::FB_CROAK); print $fh_ssd_file $str_ssd; close $fh_ssd_file; ################################################################# #Capture host and script location information. my $hostname = `hostname`; my $script_path = Cwd::abs_path($0); ################################################################# #Email Body Content. my $email_body = <<"EMAIL_BODY"; Host Name: $hostname Script path: $script_path Please check the attached files if health state shows not ok. ================================================================ Array Health ================================================================ $str_genhealth ================================================================ Capacity (Empty pools are not shown): $used_capacity EMAIL_BODY ################################################################# #Create Email, insert email body content & Attachments. Email::Stuffer ->text_body($email_body) ->subject($email_subject) ->attach_file($batteries) ->attach_file($power_supply) ->attach_file($physical_disks) ->attach_file($dpe_file) ->attach_file($ccard_file) ->attach_file($iomod_file) ->attach_file($sp_file) ->attach_file($ssd_file) ->from('Pritesh Ugrankar <me@email.com>') ->transport(Email::Sender::Transport::SMTP->new({ host => 'mysmtpserver', })) ->to('My Team <myteamdl@email.com>') ->send_or_die;

  • Comment on Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.
  • Select or Download Code

Replies are listed 'Best First'.
Re: Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.
by haukex (Archbishop) on Oct 02, 2020 at 11:57 UTC
    it runs fine if I execute it from within the directory where it's located ... However, running it by giving the path gives the following error

    This, coupled with the fact you've got relative pathnames in your script, is the very first thing I would fix. You need to have an absolute pathname somewhere, relative to which the filenames should be resolved. It either needs to be hardcoded, in a configuration file whose location is fixed, given by the user, or you can get pathnames relative to the current script's location like so:

    use warnings; use strict; use FindBin; use File::Spec::Functions qw/catfile/; use Config::Tiny; my $config_file = catfile($FindBin::Bin, 'vnxe_config.conf'); my $array_creds = Config::Tiny->read($config_file) or die "Failed to read $config_file";

    Note how you don't need to call ->new if you're also calling ->read, and note how I added a check to make sure ->read isn't returning undef (for example, if it can't find the file). You'll need to use this method of getting an absolute pathname for every filename that you don't want to be resolved relative to the current working directory.

    If you still have the same issue after doing this, please let us know.

      Hi Haukex,

      Thank you so much for the clarification. I'm the same guy you helped with your fantastic answer earlier. I have used your module and slightly modified version of your code in this script. Thank you once again.

        I have used your module

        Glad to help. Note IPC::Run3 isn't my module (IPC::Run3::Shell, which uses that module, is). By the way, in the comments in the OP you mention DRY, and this is definitely a case where it applies. Here's how I might have coded this in order to avoid as much of the repetition as possible:

        my @commands = ( { name=>'genhealth', arg=>'/sys/general', file=>'genhealthfile' }, { name=>'bat', arg=>'/env/bat', file=>'batteries' }, # ... { name=>'ssd', arg=>'/env/ssd', file=>'ssd_file' }, ); for my $cmd (@commands) { print "### Working on ", $cmd->{name}, "\n"; run3 ['uemcli', '-d', $vnxe_ip, '-u', $username, '-p', $password, $cmd->{arg}, 'show', '-detail'], undef, \my $out; my $str = decode('UTF-16', $out, Encode::FB_CROAK); my $filename = $cmd->{file}.'.txt'; open (my $fh, '>', $filename) or die "$filename: $!"; print $fh $str; close $fh; }

        Update: By the way, I don't know why you are using file mode '+>', since that's only needed for R/W access, it seems to me '>' should be enough for your case. Beware of cargo-culting!

Re: Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.
by GrandFather (Saint) on Oct 02, 2020 at 03:17 UTC

    How about you strip this down to the smallest piece of code that shows the problem? You may find I know what I mean. Why don't you? helps. You may find it helps to add print statements through your code so you at least know how far it's getting before it falls over.

    As it stands there is far too much unknown context for us to easily help.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.
by jwkrahn (Abbot) on Oct 02, 2020 at 06:11 UTC
    G:\>perl cdr_vnxe\cedar_rapids_vnxe_v2.pl Use of uninitialized value $text in substitution (s///) at G:/Strawber +ry/perl/vendor/lib/Win32/ShellQuote.pm line 85.

    There is no variable $text in the code you posted.

    $array_creds = Config::Tiny->read('vnxe_config.conf');

    This file is not available outside the directory.

      "There is no variable $text in the code you posted."

      The error is from Win32::ShellQuote, line 85.

      Hi,

      Yes you are right. I'm using that file to read the username and password which unfortunately I cannot provide here. Also there's no $text variable in my script nor am I doing any substitution. Even if I embed the username and password in the script I still get the error.

      What baffles me is the script works fine if I run it from the directory where its in. No errors whatsoever. Just when I run it with the path, the error comes up.

        "Also there's no $text variable in my script nor am I doing any substitution. Even if I embed the username and password in the script I still get the error."

        The error tells you exactly where this is coming from:

        G:\>perl cdr_vnxe\cedar_rapids_vnxe_v2.pl Use of uninitialized value $text in substitution (s///) at G:/Strawber +ry/perl/vendor/lib/Win32/ShellQuote.pm line 85.

        "What baffles me is the script works fine if I run it from the directory where its in. No errors whatsoever. Just when I run it with the path, the error comes up. "

        You have:

        my $array_creds = Config::Tiny->new(); $array_creds = Config::Tiny->read('vnxe_config.conf');

        Consider the following example:

        #!/usr/bin/perl use strict; use warnings; use Config::Tiny; my $Config = Config::Tiny->new; $Config = Config::Tiny->read( 'file.conf' ); print "$Config->{_}{var1}\n";

        When run from the directory containing your config file:

        marto@Marto-Desktop:~/code$ ./cf.pl derp

        When run from the parent directory:

        marto@Marto-Desktop:~$ ./code/cf.pl Use of uninitialized value in concatenation (.) or string at ./code/cf +.pl line 8.

        As you see, the code can't find the config file.

        #!/usr/bin/perl use strict; use warnings; use File::Basename; my $dirname = dirname(__FILE__); use Config::Tiny; my $Config = Config::Tiny->new; $Config = Config::Tiny->read( "$dirname/file.conf" ); print "$Config->{_}{var1}\n";

        Runs fine:

        marto@Marto-Desktop:~$ ./code/cf.pl derp

        Update: IPC::Run3 needs Win32::ShellQuote because you are on Windows. https://metacpan.org/source/RJBS/IPC-Run3-0.048/Makefile.PL#L13.

        $text is in the module code for Win32/ShellQuote.pm. However looking at that code isn't going to resolve the problem. The way to track this issue down is to perform a binary search. Get rid of half the code. If the bug goes away it was in the half of the code you removed. If the bug remains it is in the half you retained. Halve the chunk of code manifesting the bug then rinse and repeat.

        By definition the bug is something to do with your context when you run the script. We don't have your context so we can't debug for you. Either strip your example down to something we can run that exhibits the problem, or do the debugging yourself.

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Perl script runs fine if exec'd from the directory, but gives error if run outside the directory.
by pritesh_ugrankar (Monk) on Oct 02, 2020 at 19:21 UTC

    Respected Monks,

    Update: I wrote this answer before checking the replies here. I guess my impatience knows no bounds.

    Issue got resolved after I gave the full path to the file being read by Config::Tiny!! I am truly sorry to waste your time on this. It was my negligence and impatience that caused this.

    But, that is not worst. What is worst is, jwkrahn had indicated the same, and I completely mis understood his question!!. This issue is resolved. But as usual, thank you monks for your amazing replies. This place and Perl never cease to amaze me.

    As an aside, this issue helped me clean up the PATH variable setting in windows. It was not related to this issue, but while cleaning up the PATH, I went back and read what jwkrahn had stated and it made sense.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11122460]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (2)
As of 2024-04-25 21:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found