2016-03-15 78 views
0

我寫這樣

#!/usr/bin/perl 
my $str = "hello\nworld"; 
my $cmd = "echo -e $str"; 
system($cmd); 

,並輸出一個簡單的Perl腳本是:預計不

-e hello 
sh: 2: world: not found 

。而我想是這樣的:

hello 
world 

指出,「回聲-e」能工作correclty,因爲當我運行下面的命令,

echo -e "hello\nworld" 

輸出是正確的。

任何解決方案?

+1

因爲'echo -e'不是可移植的,所以這是一個特別糟糕的例子。對於任何真實的東西,'echo'都可以做到,你可以在Perl中更簡單地做到這一點。也許你應該使用一個不同的例子,或許更接近你想要運行的真實代碼。 – tripleee

回答

5

如果打印出來$cmd你設置後,你會看到這一點:

echo -e hello 
world 

...如果你粘貼到殼,你會得到類似的錯誤消息,雖然沒有-e

第一個問題是,當它到達shell時,該字符串缺少引號和非文字換行符。試試這個:

my $str = "hello\\nworld"; 
my $cmd = "echo -e '$str'"; 

在這種特殊情況下,你可以逃脫只是引號 - 將會有參數echo內文字換行,但只要它引用了這是合法的。

但是,您仍然會在輸出中獲得立即數-e,並且不會將\n解釋爲換行符。這是因爲perl運行的是/bin/echo,而不是內置於bash的echo。如果你想使用bash的builtin,你必須告訴perl明確運行bash。但這意味着將echo命令本身內部的參數傳遞給bash,從而引入另一個級別的引用來處理。

這裏最好的選擇是使用system的多重參數版本;它繞過第一個shell級別並直接執行該命令。我們還必須應對新行:

my $str = "hello\nworld";     # literal newline 
(my $escaped_str = $str) =~ s,\n,\\n,g; # escaped newline 

爲了從殼獲得所需的行爲,我們需要嵌入在shell命令單引號括起來的,因爲在單引號裏的東西被認爲完全從字面上由殼。在這種情況下,我們只是從Perl代碼中的文字中分配字符串,所以我們知道它包含的內容,並且不包含撇號。但是,如果它可能永遠包含撇,我們應該運行它通過另一個逃生傳球給說出來了,所以它的安全在單引號嵌入:

$escaped_str =~ s,','\\'',g;    # quote any embedded apostrophes 

有可能是你希望與逃逸替換其他字符,太 - 也許標籤或回車。這將是進行這些更改的地方。

使用轉義字符串建立bash命令:

my $command = "echo -ne '$escaped_str'"; # bash command to echo string 

手工做搜索/替換這樣很容易出錯;有很多邊緣案例需要考慮。所以,你可能也想看看CPAN模塊String::ShellQuote,在其中您可以跳過手動上述逃逸,從原始這樣的轉義字符串:

my $command = shell_quote("echo", "-ne", $str); 

一旦你有逃脫的命令字符串,請使用

system('bash', '-c', $command); 

一般,更重要的是,我會考慮更換任何shell命令用Perl本身代碼的功能;:多參數system直接與該字符串作爲參數運行的bash結果將更容易管理,並且可能更具可移植性和性能。

+0

thx,當我使用你的推薦命令時,輸出是這樣的: '-e你好 world' 但是當刪除'-e'選項('「ehco $ cmd =」echo'$ str'「')時,可以正常工作。 – user6064254

+1

繼續閱讀..我覆蓋了。 –

0
my $cmd = qq(echo -e "$str"); 

系統參數字符串中的新行類似於;。它分隔命令。爲了不發生這種情況,你需要把它放在引號內。