Reputation: 3264
From my Perl program, I am trying to run another command written in C using system
. The command requires several arguments: a string, a float, two integers, a pair of floats, and another string. I am running this as
my $arg1="electron";
my $arg2=0.511;
# more definitions
system("./fermions $arg1 $arg2 $arg3 $arg4 " .
"$arg5 $arg6 \"string\" > outfile.out");
I need to vary $arg5
to be several different float values. I made it work by setting $arg5="1.0e5"
and then running an if-statement in the for-loop to change the value as a string. I would like to be able to do this as floats, and tried
system("./fermions $arg1 $arg2 $arg3 $arg4 " .
"%e $arg6 \"string\" >outfile.out",
$arg5);
but that did not work. Is there another alternative, or is my if-statement option the only one?
Upvotes: 2
Views: 414
Reputation: 139691
Important: You should always check the return value from Perl’s system
function to determine whether the command failed.
Use Perl’s sprintf
to format the float values as in the code below. Yes, you may be able to get away with using the command as your format specifier, but you’re likely to get surprising results if the command has stray % characters elsewhere. Using two steps is safer.
#! /usr/bin/env perl
use strict;
use warnings;
my @float_values = (1.0e5, 3.14159, 2.71828);
for my $f (@float_values) {
my $arg5 = sprintf "%e", $f;
system(qq[./fermions $arg5 "string" >> outfile.out]) == 0
or warn "$0: fermions failed";
}
In case you aren’t familiar with the syntax, qq[...]
works like a double-quoted string, but the different delimiter means you don’t have to escape double-quotes in your command.
Note that I elided the other arguments for typographical purposes, but you can interpolate them along with the value of $arg5
. Another subtle change is the switch to >>
for appending rather than >
for clobbering.
Using a stand-in for fermions
#! /usr/bin/env perl
$" = "][";
warn "[@ARGV]\n";
the output of the two programs running together is
[1.000000e+05][string] [3.141590e+00][string] [2.718280e+00][string]
With respect to terminology, a system call refers to a low-level request for service from the operating system, e.g., open
, close
, unlink
, and so on. Although Perl’s system function makes use of system calls, the two concepts are distinct.
To be really safe about the shell not fudging your command-line arguments, use the techniques described in the “Safe Pipe Opens” section of perlipc. Perl’s system
and exec
functions bypass the shell when given a list of arguments rather than a single string containing the entire command.
Your situation is a little trickier because you want to redirect the standard output. The code below forks a child, sets the child’s STDOUT
to append to outfile.out
, and then runs fermion
with exec
in the child. The parent waits for the child to exit and reports any failure.
#! /usr/bin/env perl
use strict;
use warnings;
my @float_values = (1.0e5, 3.14159, 2.71828);
for my $f (@float_values) {
my $arg5 = sprintf "%e", $f;
my $pid = fork;
if (defined $pid) {
if ($pid == 0) {
my $path = "outfile.out";
open STDOUT, ">>", $path or die "$0: open $path: $!";
exec "./fermions", $arg5, "string" or die "$0: exec: $!";
}
else {
local $!;
my $pid = waitpid $pid, 0;
warn "$0: waitpid: $!" if $pid == -1 && $!;
warn "$0: fermion exited " . ($? >> 8) if $?;
}
}
else {
die "$0: fork: $!";
}
}
Upvotes: 1
Reputation:
If you want to use printf notation (like "%e"), you need to use the Perl sprintf
builtin. Otherwise you just end up passing "%e" as a literal argument.
Upvotes: 6