This is in perl Windows.
Code Snippet:
my $TestVarDirName;
my $testScript = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64";
&runAndMonitor(\@ForRun, "$MSROO/logs/Test.log");
$testScript = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/hash -m win -serial 32 $TestVarDirName -t wint"; ### Added
&runAndMonitor(\@ForRun2, "$MSROO/logs/Test2.log"); ### Added
sub runAndMonitor {
my @ForRunPerProduct = @{$_[0]};
my $logFile = $_[1];
foreach my $TestVar (@ForRunPerProduct) {
print "$testScript is the testScript command\n"; ### Line 9
$TestVarDirName = $TestVar;
$TestVarDirName = dirname ($TestVarDirName);
my $filehandle;
if ( !($pid = open( $filehandle, "-|" , " $bashexe -c \"cd $smokesBasePath \; $testScript \" >> $logFile ""))) {
die( "Failed to start process: $!" );
}
}
}
I want that in piped open command, $testScript
variable substitutes the value of $TestVarDirName
only when $testScript
is called (dynamically), and not in the start of the script.
Currently, at "line 9" (as mentioned in code snippet), I am getting U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash -t lnx64 is the testScript command
. Of course because initially at the start of script, $TestVarDirName
has no value in it, and command would work according to its initial value. How can I avoid it, and let the latest value of $TestVarDirName
be used?
CodePudding user response:
Use an anonymous sub to build the string:
my $testScriptBuilder = sub { "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $_[0] -t lnx64" };
...
foreach my $TestVar (@ForRunPerProduct) {
local $TestVarDirName = dirname($TestVar);
my $testScript = $testScriptBuilder->($TestVarDirName);
....
}
If you think that having $_[0]
instead of $TestVarDirName
in the string makes things less clear, then you could use this sub instead:
my $testScriptBuilder = sub {
my $TestVarDirName = $_[0];
return "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64"
};
The interpolation of $_[0]
(or $TestVarDirName
) in "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $_[0] -t lnx64"
is only done when the subroutine testScriptBuilder
is evaluated, which is when you actually call it with testScriptBuilder->($TestVarDirName)
. Thus, $TestVarDirName
will have the expected value (dirname($TestVar)
).
Alternatively, you could use the Template
module:
my $testScriptTemplate = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash [% TestVarDirName %] -t lnx64";
...
foreach my $TestVar (@ForRunPerProduct) {
my $TestVarDirName = dirname($TestVar);
Template->new->process(\$testScriptTemplate, { TestVarDirName => $TestVarDirName }, \my $testScript);
...
}
The downside is that you have to modify the initial string in a more intrusive manner (replacing $TestVarDirName
by [% TestVarDirName %]
). However, this is also an upside, as it allows you to specify what should be interpolated early and what shouldn't: all of the variables in the template string will be interpolated right away, while the things inside [% %]
will be interpolated later.
CodePudding user response:
Dada's answer is the sane way of doing this, but if you'd like a less sane way...
use String::Interpolate::Delayed;
my $TestVarDirName;
my $testScript = delayed "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64";
&runAndMonitor(\@ForRun, "$MSROO/logs/Test.log");
sub runAndMonitor {
my @ForRunPerProduct = @{$_[0]};
my $logFile = $_[1];
foreach my $TestVar (@ForRunPerProduct) {
print "$testScript is the testScript command\n"; ### Line 9
$TestVarDirName = $TestVar;
$TestVarDirName = dirname ($TestVarDirName);
my $filehandle;
if ( !($pid = open( $filehandle, "-|" , " $bashexe -c \"cd $smokesBasePath \; $testScript \" >> $logFile ""))) {
die( "Failed to start process: $!" );
}
}
}
CodePudding user response:
I think there's a much simpler way to go here. Set up a template for the string you want, then fill in the placeholders when you are ready to use it. No fancy subroutine tricks or modules:
my $testScript_template = "U:/perl.exe ... %s -t lnx64";
sub runAndMonitor {
...
foreach my $TestVar (@ForRunPerProduct) {
...
$TestVarDirName = dirname ($TestVarDirName);
$testScript = sprintf $testScript_template, $TestVarDirName;
...
}
}
But I might move that template into the smallest scope it needs:
sub runAndMonitor {
...
foreach my $TestVar (@ForRunPerProduct) {
state $testScript_template = "U:/perl.exe ... %s -t lnx64";
...
$TestVarDirName = dirname ($TestVarDirName);
$testScript = sprintf $testScript_template, $TestVarDirName;
...
}
}