關於perl中的反引號(``),system和exec
在perl中反勾號(``),system和exec都用來實行號令,這篇文章將給我們先容它們各自的利用方式,接洽,以及區別。
一、利用方式
1. 反勾號(``)
起首,我們有號令輸入操縱符,也叫反勾號操縱符,由於它看起來象如許:
$info = `finger $user`;
一個用反勾號(手藝上叫重音號)引起的字串起首舉行變數替代,就象一個雙引號引起的字串一樣。獲得的成果然後被體系看成一個號令行,並且阿誰號令的輸出成為偽文本的值。(這是一個近似 Unix shell 的模組。)在標量情況裡,返回一個包羅全部輸出的字串。在列表情況裡,返回一列值,每行輸出一個值。(你可以經由過程設定 $/ 來利用分歧的行竣事符。)
每次計較偽文本的時辰,該號令都得以實行。該號令的數字狀況值保留在 $?(參閱第二十八章擷取 $? 的詮釋,也被稱為 $CHILD_ERROR )。和這條號令的 csh 版本分歧的是,對返回資料不做任何轉換——分行符號仍舊是分行符號。和全部 shell 分歧的是,Perl 裡的單引號不會埋沒號令行上的變數,使之制止代換。要給 shell 通報一個 $,你必需用反斜線把它埋沒起來。我們上面的 finger 例子裡的 $user 被 Perl 代換,而不是被 shell。(由於該號令 shell 處置,參閱第二十三章,平安,看看與平安有關的內容。)
反勾號的一樣平常情勢是 qx//(意思是“引起的實行”),但這個操縱符的感化完全和通俗的反勾號一樣。你只要選擇你的引起字元就行了。有一點和引起的偽函數近似:若是你可巧選擇了單引號做你的分開符,那號令行就不會舉行雙引號代換;
$perl_info = qx(ps $$); # 這裡 $$ 是 Perl 的處置工具 $perl_info = qx'ps $$'; # 這裡 $$ 是 shell 的處置工具
下面是一個例子:
在筆者的F盤中存在一個perl檔案F://Demo3.pls,它的感化便是被別的一個法式F://Demo1.pls挪用,然後F://Demo3.pls讀取log3.log中的資料。
Demo3.pls
#!/usr/bin/perl -w
use strict;
use warnings;
unless(open(FILE_H,"
print "Can not open the file";
}
my @str = ;
my $count = @str;
close(FILE_H);
for(my $i = 0;$i<$count;$i++){
print "$str[$i]";
}
Demo.pls
#!/usr/bin/perl –w
my @str = qx/perl F://Demo3.pls/;#大概` perl F://Demo3.pls `結果#一樣
print "@str";
Log3.log
起首,我們有號令輸入操縱符,也叫反勾號操縱符,由於它看起來象如許:
$info = `finger $user`;
一個用反勾號(手藝上叫重音號)引起的字串起首舉行變數替代,就象一個雙引號引起的字串一樣。獲得的成果然後被體系看成一個號令行,並且阿誰號令的輸出成為偽文本的值。(這是一個近似 Unix shell 的模組。)在標量情況裡,返回一個包羅全部輸出的字串。在列表情況裡,返回一列值,每行輸出一個值。(你可以經由過程設定 $/ 來利用分歧的行竣事符。)
代碼詮釋,當實行Demo.pls時,my @str = qx/perl F://Demo3.pls/;這一句會被操縱體系挪用而且啟動Demo3.pls,然後Demo3.pls會讀取log3.log中的資料。
我們首要存眷的是my @str = qx/perl F://Demo3.pls/;這句中的傳回值@str,我們都知道@str是一個列表情況,反勾號返回Demo3.pls中的print的列印值,固然我們也可以利用標量情況,比方,my $str = qx/perl F://Demo3.pls/;如許也可以一次性的掏出全部的資料。
末了總結:反勾號返回的是號令行返回的print的數值。詳細的詮釋看上面的申明。
2. System
l system PATHNAME LIST
l system LIST
這個函數為你實行任何體系裡的法式並返回該法式的退出狀況——而不是它的輸出。要捕捉號令行上的輸出,你應該用反勾號大概 qx//。system 函數的運轉很是近似 exec,只不外 system 先做一個 fork,然後在 exec 之後期待實行的法式的竣事。也便是說它為你運行這個法式而且在它完成之後返回,而 exec 用新的法式取代你啟動並執行法式,以是若是替代樂成的話它從不返回。
參數的處置因參數的數量的分歧而分歧,就象在 exec 裡形貌的那樣,包羅判定是否挪用 shell 以及你是否用聲明別的一個 PATHNAME 的方式利用了該函數其他的名稱。
由於 system 和反勾號梗阻 SIGINT 和 SIGQUIT,以是向那些正在如許啟動並執行法式發送這些旌旗燈號之一(好比經由過程一個 Control-C)時並不會間斷你的主法式。可是你啟動並執行別的一個法式簡直收到這個旌旗燈號。請查抄 system 的傳回值,判定你啟動並執行法式是否正常退出。
@args = ("command", "arg1", "arg2");
system(@args) == 0
or die "system @args failed: $?"
傳回值是和該函數經由過程 wait(2) 體系挪用返回的一樣的退出狀況。在傳統的語意裡,要擷取現實的退出值,要除以 256 大概右移 8 位。這是由於低 8 位裡有一些其他的工具。(現實上是其他的兩些工具。)最低七位標識殺死該曆程的旌旗燈號號碼(若是有的話),而第八位標識該曆程是否傾倒了焦點。你可以經由過程 $?($CHILD_ERROR)來查抄全部失效大概性,包羅旌旗燈號和焦點傾倒:
$exit_value = $? >> 8;
$exit_value = $? & 127; # 大概 0x7f, 0177, 0b0111_1111
$dumped_core = $? & 128; # 大概 0x80, 0200, 0b1000_0000
若是該法式是經由過程體系 shell (註:界說為 /bin/sh 大概任安在你的平台上故意義的工具,但不是那些使用者可巧在某個時辰用到的 shell。)啟動並執行,這大概是由於你只有一個參數並且該參數內裡有 shell 元字元,那麼凡是返回碼受阿誰 shell 的怪癖和功效的影響。換句話說,在這種環境下,你大概無法擷取我們前面形貌了具體資訊。
3. exec
o exec PATHNAME LIST
o exec LIST
exec 函數竣事當出息序的運行而且實行一條外部號令而且決不返回!!!若是你但願在該號令退出之後規複節制,那麼你應該利用 system。exec 函數只有在該號令不存在以及該號令是直接實行而沒有經由過程你的體系的號令行 shell(下面會商)實行的時辰才失敗並返回假。
若是只有一個標量參數,那麼 exec 查抄該參數是否 shell 的元字元。若是找到元字元,那麼它代表的全部參數都通報給體系的尺度號令行詮釋器(在 Unix 裡是 /bin/sh)。若是沒有如許的元字元,那麼該參數被割裂成單詞然後直接實行,出於服從思量,如許做繞開了全部 shell 處置的過荷。並且若是該法式沒有退出,如許也給你更多錯誤規複的節制。
若是在 LIST 裡有多於一個參數,大概若是 LIST 是一個帶有跨越一個值的數組,那麼就決不會利用體系的 shell。如許也繞開了 shell 對該號令的處置。在參數中是否呈現元字元並不影響這個列表觸發特徵,這麼做也是有平安思量的法式的比力好的做法,由於它不會把本身表露在潛伏的 shell 逃逸之中。
下面的例子令當前啟動並執行 Perl 法式用 echo 法式取代自身,然後它就列印出當前的參數列表:
exec 'echo', 'Your arguments are: ', @ARGV;
下面這個例子表現了你可以 exec 一個流水線,而不但僅是一個法式:
exec "sort $outfile | uniq"
or die "Can't do sort/uniq: $!/n";
凡是,exec 從不返回——就算它返回了,它也老是返回假,而且你應該查抄 $! 找出什麼工具犯錯了。要注重的是,在老版本的 Perl 裡,exec(和 system)並不革新你的輸出緩衝,以是你必要在一個或更多個檔案控制代碼上經由過程設定 $| 開啟號令緩衝功效以制止在 exec 的環境下丟失輸出,大概在 system 的環境下打亂了輸出挨次。在 Perl 5.6 裡環境大抵如斯。
若是你讓操縱體系在一個現有的曆程裡運行一個新的法式(好比 Perl 的 exec 函數做的如許),你要報告體系要實行的法式在那邊,可是你也報告了這個新的法式(經由過程它的第一個參數)是什麼法式實行了它。風俗上,你報告它的名字只是該法式的位置的一個拷貝,但這麼做不是必需的,由於在 C 說話的層級上,有兩個自力的參數。若是這個名字不是拷貝,那麼你就大概看到奇異的成果:這個新法式以為本身因此一個和它地點的現實路徑名完全分歧的名字啟動並執行。凡是如許對那些滿腹困惑的法式來說沒什麼題目,但有些法式簡直體貼本身的名字,而且按照本身的名字的轉變會有分歧的性格。好比,vi 編纂器會看看本身是作為“vi”仍是作為“view”挪用的。若是作為“view”,那麼它就主動開啟唯讀模式,就好象它是帶著 -R 號令行選項挪用的一樣。
這個時辰便是 exec 的可選 PATHNAME 參數起感化的處所了。從語意上來看,它放在間接工具的位置,就好象 print 和 printf 的檔案控制代碼一樣。是以,它並不必要在背面有一個工具,由於它現實上不是參數列表的一部門。(從某種意義上來說,Perl 與操縱體系採納的方式正相反,它以為第一個參數是最主要的,而且若是它分歧那麼就讓你點竄路徑名。)好比:
$editor = "/usr/bin/vi";
exec $editor "view", @files # 觸發唯讀模式
or die "Couldn't execute $editor: $!/n";
和任何其他間接工具一樣,你也可以用一個包羅肆意代碼的塊取代上面這個保留法式名的簡略標量,如許就可以把前面這個例子簡化為:
exec { "/usr/bin/vi" } "view" @files # 觸發唯讀模式
or die "Couldn't execute $editor: $!/n";
如前所述,exec 把一個分離的參數列表看成一個它應該繞開 shell 處置的標記。不外,仍舊有一個處所大概把你拌倒。exec 挪用(以及 system)不克不及區別單個標量參數和一個只有一個元素的列表。
@args = ("echo surprise") # 只有一個元素在列內外
exec @args # 仍舊大概有 shell 逃逸
or die "exec: $!"; # 由於 @args == 1
為了制止這種環境,你可以利用 PATHNAME 文法,明白地把第一個參數當路徑名複製,如許就逼迫其他的參數詮釋成一個列表,縱然現實上只有一個元素:
exec { $args[0] } @args # 就算是只有一個元素的列表也平安了
or die "can't exec @args: $!";
第一個沒有花括弧的版本,運行 echo 法式,給它通報“surprise”做參數。第二個版本不是如許——它試圖運行一個字面上叫 echo surprise 的法式,但找不到(我們但願如斯),然後把 $! 設定為一個非零值以暗示失敗。
由於 exec 函數凡是是緊跟在 fork 之後挪用的,以是它假定任何原先一個 Perl 曆程停止的時辰要產生的工作都被紕漏。在 exec 的時辰,Perl 不會挪用你的 END 塊,也不會挪用與任何工具相干的 DESTROY 方式。不然,你的子曆程竣事的時辰會做那些你籌辦在父曆程裡做的清算事情。(我們但願在實際糊口中便是如斯。)
由於把 exec 看成 system 用是一個很是遍及的錯誤,以是若是你帶著風行的 -w 號令行開關運行,大概你用了 use warnings qw(exec syntax) 用法的時辰,若是 exec 背面隨著的語句不是 die,warn,或則 exit,那麼 Perl 就會告誡你。若是你真的想在 exec 背面跟一些其他的語句,你可以利用下面兩種氣概之一以制止告誡:
exec ('foo) or print STDERR "couldn't exec foo: $!";
{ exec ('foo') }; print STDERR "couldn't exec foo: $!";
正如上面的第二行表現的那樣,若是挪用 exec 的時辰是一個塊裡的末了一條語句,那麼就可以免於告誡。