2012-04-21 60 views
2

從我的Perl程序中,我試圖運行使用system用C編寫的另一個命令。該命令需要幾個參數:一個字符串,一個浮點數,兩個整數,一對浮點數和另一個字符串。我運行這個爲如何使用科學記數法制作Perl的system()格式參數?

my $arg1="electron"; 
my $arg2=0.511; 
# more definitions 
system("./fermions $arg1 $arg2 $arg3 $arg4 " . 
     "$arg5 $arg6 \"string\" > outfile.out"); 

我需要改變$arg5是幾個不同的浮點值。我通過設置$arg5="1.0e5"然後在for循環中運行if語句將該值更改爲字符串來實現它的工作。我想能夠做到這一點花車,並試圖

system("./fermions $arg1 $arg2 $arg3 $arg4 " . 
     "%e $arg6 \"string\" >outfile.out", 
     $arg5); 

但這並沒有奏效。還有另外一種選擇,還是我的if語句選項是唯一的選項?

+0

請考慮使用'system LIST'或'system {PROGRAM} LIST' [invocation](http://perldoc.perl.org/functions/system.html)。當有一天,在許多重構之後,'$ arg2'變成'「; rm -rf /」',這將更加安全。您將無法使用shell輸出重定向,但您可以自己打開'outfile.out'並將其複製到STDOUT或將'。/ fermions'包裝在shell腳本中以捕獲輸出。 – pilcrow 2012-04-21 03:17:26

+0

瞭解。我會爲此修改我的代碼,但我現在正在問這個問題以備將來使用。 – 2012-04-21 12:13:16

回答

6

如果要使用printf表示法(如「%e」),則需要使用內置的Perl sprintf。否則,你最終會傳遞「%e」作爲文字參數。

1

重要:你應該總是檢查從Perl的system函數的返回值,以確定該命令是否失敗。

使用Perl的sprintf來格式化float值,如下面的代碼所示。是的,您可能能夠避免使用該命令作爲格式說明符,但如果該命令在其他地方存在零星字符,則可能會得到令人驚訝的結果。使用兩個步驟更安全。

#! /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"; 
} 

如果你不熟悉的語法,qq[...]的作品就像一個雙引號字符串,但不同的分隔符意味着你不必在你的命令逃脫雙引號。

請注意,我爲了印刷目的而忽略了其他參數,但您可以將它們與值$arg5一起插值。另一個微妙的變化是切換到>>爲附加而不是>進行破壞。

使用替身fermions

#! /usr/bin/env perl 
$" = "]["; 
warn "[@ARGV]\n"; 

一起運行的兩個程序的輸出是

[1.000000e+05][string] 
[3.141590e+00][string] 
[2.718280e+00][string]

對於術語中,一個系統調用指的是用於一個低級別的請求來自操作系統的服務,例如open,closeunlink等等。雖然Perl的系統函數使用系統調用,但這兩個概念是不同的。

要成爲確實有關shell不會欺騙命令行參數的安全問題,請使用「Safe Pipe Opens」 section of perlipc中描述的技術。在給定參數列表時,Perl的systemexec函數繞過了shell,而不是包含整個命令的單個字符串。

你的情況有點棘手,因爲你想重定向標準輸出。下面的代碼將孩子分叉,將孩子的STDOUT設置爲追加到outfile.out,然後在兒童中運行fermionexec。父母等待孩子退出並報告任何失敗。

#! /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: $!"; 
    } 
}