interp(3tcl)

NAME
interp - 建立和操縱 Tcl 直譯器

總覽 SYNOPSIS
interp option ?arg arg ...?

描述 DESCRIPTION

這個命令建立一個或多個新的 Tcl 直譯器，並使其與建立(它們的)直譯器在相同的應用中共存。建立直譯器的直譯器叫做主直譯器(master)而新直譯器叫做從直譯器(slave)。主直譯器可以建立任意數目的從直譯器，每個從直譯器也可以自己建立增添的從直譯器而成為它們的主直譯器，這將導致直譯器的一個等級層次(hierarchy)。

每個直譯器相對其他直譯器是獨立的: 它有給命令、過程、和全域性變數的自己的名字空間。一個主直譯器可以使用叫別名(alias)的機制建立它的從直譯器與它自身間的連線。別名是在一個從直譯器中的一個命令，呼叫它時，導致在它的主直譯器或其他從直譯器中呼叫一個命令。直譯器之間的唯一其他連線是通過環境變數(env 變數)，它通常被在這個應用中的所有直譯器共享。注意給檔案的名字空間(比如由 open命令返回的名字)不在直譯器之間共享。提供顯式的命令來共享檔案和把到開啟檔案的引用從一個直譯器轉換(transfer)到另一個。

interp命令還提供對安全(safe)直譯器的支援。一個安全直譯器是一個功能被嚴格限制了的從直譯器，這樣就可以執行不可信任的指令碼而不用害怕它們毀壞其他直譯器或這個應用的環境。例如，安全直譯器不能訪問所有 IO 通道建立命令和子過程建立命令。 詳情參見下面的 SAFE INTERPRETERS (安全的直譯器) 章節。未從安全的直譯器中去除有危險的功能；但是，它們是隱藏的，所以只有可信任的直譯器可以獲得到它們的訪問。隱藏命令的詳細解釋請參見下面的 HIDDEN COMMANDS (隱藏命令) 章節。可以使用別名機制來在從直譯器和它的主直譯器之間進行受保護的通訊(類似於一個核心呼叫)。別名機制工作的詳情參見下面的 ALIAS INVOCATION (別名呼叫)章節。

一個限定的(qualified)直譯器的名字是一個適當的 Tcl 列表，它包含在這個直譯器層次中它的祖先的一個子集，終結於以它的直接上級(immediate)主直譯器命名的字串。直譯器名字是相對於在其中使用它的哪個直譯器的。例如，如果 a 是當前直譯器的一個從直譯器並且它有一個從直譯器 a1，它依次有一個從直譯器 a11，在a 中 a11 的限定的名字是列表 a1 a11。

下面描述的 interp命令接受限定的直譯器名字作為引數；命令在其中求值的直譯器總是可以作為 {}來引用(空列表或字串)。注意除了通過別名之外，在一個從直譯器中不可能通過名字引用一個主(祖先)直譯器。還有，沒有通過它可以引用在應用中建立的第一個直譯器的全域性名字。這兩種限制的目的都是為了安全。

INTERP 命令 COMMAND

使用 interp 命令建立、刪除、和操縱從直譯器，並在直譯器之間共享或轉換通道。依賴於 option 引數，它可以有下列一些形式:

interp alias srcPath srcCmd
    返回一個 Tcl 列表，它的元素是與叫做 srcCmd的別名有關的 targetCmd 和 args(在建立別名時指定所有這些值；在從直譯器中實際的源命令如果被重新命名的話可能與 srcCmd 不同)。

interp alias srcPath srcCmd {}
    刪除在從直譯器中用 srcPath 標識的給 srcCmd 的別名。srcCmd 引用在其下建立別名的名字；如果 源命令已經被重新命名，則刪除重新命名後的命令。

interp alias srcPath srcCmd targetPath targetCmd ?arg arg ...?
    這個命令在一個從直譯器和其他直譯器之間建立一個別名(關於在一個從直譯器和它的主直譯器之間建立別名請參見下面的 alias 從命令)。在這個命令中，兩個從直譯器可以在呼叫這個命令的直譯器底下的直譯器層次中的任何位置。SrcPath和 srcCmd 標識這個別名的來源。SrcPath 是一個 Tcl 列表，它的元素選擇一個特定的直譯器。例如，“a b”標識一個直譯器 b，它是直譯器 a 的一個從直譯器，a直譯器是呼叫(命令)的直譯器的一個從直譯器。一個空列表指定呼叫這個命令的直譯器。srcCmd給出一個新命令的名字，將在源直譯器中建立它。TargetPath和 targetCmd 指定一個目標直譯器和命令，和 arg 引數，如果有的話，給 targetCmd 指定增補的引數，它們在 srcCmd 呼叫中指定的所有引數的前面。TargetCmd在這個呼叫的時候可以被取消定義(undefine)了，或者它已經存在了；它不由這個命令來建立。別名安排在源直譯器中呼叫給定源命令的時候在目標直譯器中呼叫給定目標命令。詳情參見下面的 ALIAS INVOCATION (別名呼叫)章節。

interp aliases ?path?
    這個命令返回給在用 path 表示的直譯器中定義的別名的所有源命令的名字一個 Tcl 列表。

interp create ?-safe? ?--? ?path?
    建立用 path 標識的一個從直譯器和叫做從命令(slave command)的一個新命令。從命令的名字是 path的最後一個成員。在其中建立新的從直譯器和從命令的直譯器由從 path 中去除最後一個成員所獲得的路徑來標識。例如，如果 path 是 a b c 則一個新的從直譯器和叫做 c的從命令建立在用路徑 a b 標識的從直譯器中。可以使用從命令先下面描述的那樣操縱新直譯器。如果省略了 path， Tcl 建立 interpx 形式的一個唯一的名字，這裡的 x是一個整數，並用於直譯器和從命令。如果指定了 -safe開關(或者主直譯器是一個安全直譯器)，新的從直譯器將建立成功能有限的一個安全直譯器；否則從直譯器將包含 Tcl 內建命令和變數的全集。使用 -- 開關來標記開關的結束；如果路徑是象 -safe 這樣的一個特殊的值的時候需要這個開關。這個命令的結果是新直譯器的名字。一個從直譯器的名字在它的主直譯器的所有從直譯器中必須是唯一的；如果在這個主直譯器中用給定名字(標識)的一個從直譯器已經存在則發生一個錯誤。

interp delete ?path ...?
    刪除用可選的 path 引數給出的零個或多個直譯器，並且對於每個直譯器，它還刪除它的所有從直譯器。這個命令還刪除給每個被刪除的直譯器的從命令。對於每個 path 引數，如果叫這個名字的直譯器不存在，這個名字將引發一個錯誤。

interp eval path arg ?arg ...?
    這個命令用與 concat命令相同的方式串聯所有的 arg 引數，接著在用 path 標識的直譯器中把結果字串作為一個 Tcl 指令碼來求值。把這個求值的結果(如果發生錯誤的話，包括象 errorInfo和 errorCode 變數這樣的錯誤資訊)返回給呼叫(命令)的直譯器。

interp exists path
    如果在這個主直譯器中存在用 path 指定的從直譯器則返回 1，否則返回 0。如果省略了 path，使用呼叫(命令)的直譯器。

interp expose path hiddenName ?exposedCmdName?
    在用 path 表示(denote)的直譯器中，使隱藏的命令 hiddenName 暴露(expose)，最終把它帶回在一個新的exposedCmdName 名字之下(目前只接受沒有任何:: 的一個全域性名字空間名字)。如果有目標名字的一個暴露的命令已經存在，這個命令失敗。隱藏命令的詳情參見下面的HIDDEN COMMANDS (隱藏命令)章節。

interp hide path exposedCmdName ?hiddenCmdName?
    在用 path 表示(denote)的直譯器中，使暴露的命令 exposedCmdName 隱藏，並把它重新命名成隱藏命令 hiddenCmdName，如果未給出 hiddenCmdName 則保持相同的名字。如果有目標名字的一個隱藏的命令已經存在，這個命令失敗。目前 exposedCmdName 和 hiddenCmdName二者不能不能包含名字空間限定符，否則將引發一個錯誤。即使當前名字空間不是全域性名字空間，仍在全域性名字空間中查詢要被 interp hide隱藏的命令。這防止從直譯器通過使當前的名字空間不同於全域性名字空間(的方式)，來愚弄主直譯器去隱藏錯誤的命令。隱藏命令的詳情參見下面的HIDDEN COMMANDS (隱藏命令)章節。

interp hidden path
    返回在用 path 標識的直譯器中所有隱藏命令的名字的一個列表。

interp invokehidden path ?-global? hiddenCmdName ?arg ...?
    在由 path 表示的直譯器中用提供的引數呼叫隱藏命令 hiddenCmdName 。對引數不(進行)替換或求值。如果存在 -global 標誌，在目標直譯器的全域性層次上呼叫隱藏命令；否則在當前的呼叫框架 (frame)上呼叫它並且可以訪問呼叫框架內部和外部的區域性變數。隱藏命令的詳情請參見下面的HIDDEN COMMANDS (隱藏命令)章節。

interp issafe ?path?
    如果由 path 指定的直譯器是安全的則返回 1，否則返回 0。

interp marktrusted path
    標記用 path 標識的直譯器是可信任的。不暴露隱藏命令。這個命令只能在可信任的直譯器中呼叫。如果由 path標識的直譯器已經是可信任的，則這個命令沒有影響。

interp share srcPath channelId destPath
    在用 srcPath 標識的直譯器和用 destPath 標識的直譯器之間導致用 channelId標識的 IO 通道變成共享的。兩個直譯器在這個 IO通道上由相同的許可權。兩個直譯器必須關閉它來關閉低層的 IO 通道；在銷燬一個直譯器的時候自動關閉在這個直譯器中可訪問的 IO 通道。

interp slaves ?path?
    返回與用 path 標識的直譯器相關的所有從直譯器的名字的一個 Tcl 列表。如果省略了 path，使用呼叫(命令)的直譯器。

interp target path alias
    返回描述給一個別名的目標直譯器的一個 Tcl 列表。用一個直譯器路徑和源命令名指定這個別名， 就象在上面的 interp alias 中那樣。目標直譯器的名字被返回為相對於呼叫(命令)的直譯器的一個直譯器路徑。如果給這個別名的目標直譯器是呼叫(命令)的直譯器則返回一個空列表。如果給別名的目標直譯器不是呼叫(命令)的直譯器或是它的後代之一則生成一個錯誤。在呼叫這個命令的時候目標命令不是必須定義的。

interp transfer srcPath channelId destPath
    導致用 channelId 標識的 IO 通道，在用 destPath 標識的直譯器中變成可獲得的，而在用 srcPath 標識的直譯器中變成不可獲得的。

SLAVE 命令 COMMAND

對於每個用 interp 建立的從直譯器，在主直譯器中建立名字與這個新直譯器相同的一個新 Tcl 命令。可以使用這個命令呼叫在這個直譯器上的各種操作。它有下面的一般形式:
    slave command ?arg arg ...?
Slave 是直譯器的名字，command 和 args確定這個命令的具體行為。這個命令有效形式有:

slave aliases
    返回一個 Tcl 列表，它的元素是在 slave 中的所有別名的名字。返回的名字是建立別名時使用的 srcCmd 的值(如果它們已經被重新命名，則它可以同這個命令的當前的名字不相同)。

slave alias srcCmd
    返回一個 Tcl 列表，它的元素是與叫做 srcCmd 的別名相關的 targetCmd 和 args(在建立這個別名的時候指定所有這些值；在從直譯器中的實際的源命令如果被重命令則可能與 srcCmd不同)。

slave alias srcCmd {}
    在從直譯器中刪除給 srcCmd 的別名。srcCmd 參照在其下建立別名的那個名字；如果源命令已經被重新命名，則刪除重新命名後的命令。

slave alias srcCmd targetCmd ?arg ..?
    建立一個別名，當在slave 中呼叫 srcCmd 的時候, 在主直譯器中呼叫 targetCmd 。把 arg 引數作為補充的引數傳遞給 targetCmd ，這些引數在 srcCmd 的呼叫中傳遞的任何引數之前。詳情參見下面的ALIAS INVOCATION (別名呼叫)章節。

slave eval arg ?arg ..?
    這個命令用與 concat 命令相同的方式串聯所有的 arg 引數，接著在 slave 中把結果字串作為一個 Tcl 指令碼來求值。把這個求值的結果(如果有錯誤發生，包括象 errorInfo 和 errorCode 變數這樣的錯誤資訊)返回給呼叫(命令)的直譯器。

slave expose hiddenName ?exposedCmdName?
    這個命令暴露在 slave 的隱藏的命令 hiddenName，最終把它帶回在一個新的exposedCmdName 名字之下(目前只接受沒有任何:: 的一個全域性名字空間名字)。如果有目標名字的一個暴露的命令已經存在，這個命令失敗。隱藏命令的詳情參見下面的HIDDEN COMMANDS (隱藏命令)章節。

slave hide exposedCmdName ?hiddenCmdName?
    這個命令隱藏在從直譯器中暴露的命令 exposedCmdName，並把它重新命名成隱藏命令 hiddenCmdName，如果未給出hiddenCmdName 則保持相同的名字。如果有目標名字的一個隱藏的命令已經存在，這個命令失敗。目前 exposedCmdName和 hiddenCmdName二者不能不能包含名字空間限定符，否則將引發一個錯誤。即使當前名字空間不是全域性名字空間，仍在全域性名字空間中查詢要被隱藏的命令。這防止從直譯器通過使當前的名字空間不同於全域性名字空間(的方式)，來愚弄主直譯器去隱藏錯誤的命令。隱藏命令的詳情參見下面的HIDDEN COMMANDS (隱藏命令)章節。

slave hidden
    返回在 slave 中所有隱藏的名字的一個列表。

slave invokehidden ?-global hiddenName ?arg ..?
    這個命令在 slave 中用提供的引數呼叫隱藏的命令 hiddenName。對這些引數不進行求值或替換。如果給出了 -global標誌，則在這個從直譯器的全域性層次上呼叫這個命令；否則在當前呼叫框架上呼叫它並可訪問這個呼叫框架內部或外部的區域性變數。隱藏命令的詳情參見下面的HIDDEN COMMANDS (隱藏命令)章節。

slave issafe
    如果從直譯器是安全的則返回 1，否則返回 0。

slave marktrusted
    標記從直譯器為可以信任的。只可以被可信任的直譯器呼叫。這個命令不暴露在這個從直譯器中的任何隱含命令。如果這個命令已經是可以信任的了，則這個命令沒有影響。

安全直譯器 SAFE INTERPRETERS

一個安全直譯器是一個功能受限制的直譯器，所以執行從最惡毒的敵人那裡來的任意指令碼都是安全的而不用害怕這個指令碼毀壞包圍它的(enclosing)應用或你的計算環境的其餘部分。要使一個直譯器安全，要從這個直譯器中刪除特定的命令和變數。例如，刪除在磁碟上建立檔案的命令，和刪除exec命令，因為它可通過子程序導致破壞。通過建立到主直譯器的別名，它小心的檢查它們的引數並提供對設施的一個安全子集的受限制的訪問，可以提供對這些設施的有限的訪問。例如，在一個特定的子目錄中允許檔案建立，和允許對仔細選擇的和一個固定的程式的集合的子程序呼叫。

通過給 interp create 命令指定 -safe開關來建立一個安全的直譯器。進而，一個安全直譯器建立的任何從直譯器都是安全的。

建立的安全直譯器準確的有下列的內建的命令集:

    after	append	array	binary
    break	case	catch	clock
    close	concat	continue	eof
    error	eval	expr	fblocked
    fcopy	fileevent	flush	for
    foreach	format	gets	global
    history	if	incr	info
    interp	join	lappend	lindex
    linsert	list	llength	lrange
    lreplace	lsearch	lsort	namespace
    package	pid	proc	puts
    read	regexp	regsub	rename
    return	scan	seek	set
    split	string	subst	switch
    tell	trace	unset	update
    uplevel	upvar	variable	vwait
    while

interp create 建立一個安全直譯器時下列命令是隱藏的:

    cd	exec	exit	fconfigure
    file	glob	load	open
    pwd	socket	source	vwait

以後這些命令可以作為 Tcl 過程或別名來重新建立，或用 interp expose暴露出來。

除此之外，在一個安全直譯器中不存在 env變數，所以不能同其他直譯器共享環境變數。env 變數可能造成一次安全冒險，因為使用者可能在某個環境變數中儲存敏感資訊。例如，PGP 手冊建議在環境變數 PGPPASS 中儲存 PGP 私有金鑰。讓不可信任程式碼可以在安全直譯器中訪問這個變數將招致一次安全冒險。

如果擴充套件被裝載到安全直譯器中，它們也可以限制它們自己功能來排除不安全的命令。對擴充套件的安全性的管理的討論參見Safe-Tcl 和 load Tcl 命令的手冊條目。

別名呼叫 ALIAS INVOCATION

精心的設計了別名機制，所以在安全的從直譯器中執行不可信任的指令碼是安全的而別名的目標是一個可信任的主直譯器。最保證安全性的最重要的事情是確保從從直譯器傳遞到主直譯器的資訊在主直譯器中永不被求值或替換；如果這種情況發生了，它將開啟在從直譯器中的某個邪惡的指令碼來在主直譯器中呼叫任意函式，這將危及安全。

當從直譯器中呼叫一個別名的源(命令)的時候，在分析這個命令時進行常規的 Tcl 替換。在源直譯器中完成這些替換，就象對在這個直譯器中的呼叫的其他命令一樣。源命令的命令過程接受它的引數並把它們與給這個別名的 targetCmd和 args 融合起來建立一個新的引數陣列。如果 srcCmd的字是``srcCmd arg1 arg2 ... argN''，則新的字集將是``targetCmd arg arg ... arg arg1 arg2 ... argN''。這裡的 targetCmd和 args 是在建立別名的時候提供的值。接著用 TargetCmd來在目標直譯器中定位(locate)一個命令過程，並且用新的引數集來呼叫這個命令過程。如果在目標直譯器中沒有叫做 targetCmd 的命令則發生一個錯誤。在這個字上不進行補充的替換:不通過常規的 Tcl 求值機制，直接呼叫目標命令過程。所以在每個字上精確的進行一次替換: 在分析建立這個別名的命令的時候替換 targetCmd 和 args，當在源直譯器中分析這個別名的源命令的時候替換 arg1 - argN。

在安全直譯器中給別名寫 targetCmds 的時候，給它的引數永遠不被求值或替換是非常重要的，因為這將提供一種逃逸機制，使從直譯器可以執行在主直譯器中的任意程式碼。這將危及系統的安全。

隱藏命令 HIDDEN COMMANDS

安全直譯器嚴重的限制了在其中執行的 Tcl 程式可獲得的功能。允許不可信任的 Tcl 程式訪問這些功能是不安全的，因為它們可以在這個環境中被用於各種攻擊。但是，有時在安全直譯器的上下文中有使用危險的功能的合理需要。例如，有時一個程式必須 source 到直譯器中。另一個例子是 Tk，在這裡視窗被繫結到與一個特定直譯器關聯的視窗層次當中；一些潛在的危險函式，比如視窗管理，必須在這個直譯器上下文中的那些視窗上進行。

interp 命令提供了對這個問題的一種隱藏命令形式的解決方案。不是從安全直譯器中整個的刪除危險的命令，而是隱藏這些命令，所以它們變成對在這個直譯器中執行的 Tcl 指令碼是不可獲得的。但是，這個安全直譯器的任何可信任的祖先可以使用 interp invoke，在這個安全直譯器的上下文中，呼叫這些隱藏命令。隱藏命令和暴露命令駐留在分開的名字空間中。在一個直譯器中可以定義叫相同名字的隱藏命令和暴露命令。

在別名呼叫期間，在主直譯器中呼叫的過程體中可以呼叫在從直譯器中的隱藏命令。例如，在一個從直譯器中可以給 source 建立一個別名。當在這個從直譯器中呼叫它的時候，呼叫在主直譯器中的一個過程來檢查這個操作是否是允許的(比如，是否允許這個從直譯器訪問的它要求source 的檔案)。接著這個過程在從直譯器中呼叫隱藏的 source命令來實際裝載(source)這個檔案的內容。注意在從直譯器中存在來著兩個叫 source 的命令: 別名和隱藏命令。

因為一個主直譯器可以把呼叫一個隱藏命令作為處理一個別名呼叫的一部分，必須非常小心的避免對通過別名呼叫傳遞來的任何引數進行求值。否則，惡意的從直譯器可以導致一個可信任的代表它們來執行危險的命令。這個主題的完整討論參見ALIAS INVOCATION (別名呼叫)章節。要避免這個問題，對 interp invokehidden的引數不要進行替換或求值。

不允許安全直譯器呼叫它自身中或它後代中的隱藏命令。這防止安全從直譯器訪問在自身中或它們的後代中的隱藏命令。

一個可信任的直譯器可以使用 interp expose和 interp hide 來操縱一個直譯器中的隱藏命令的集合。interp expose 命令把在用 path 標識的直譯器中一個隱藏命令移動到暴露命令的集合中，在這個過程中可能重新命名這個命令。如果叫目標名字的一個暴露的命令已經存在，這個操作失敗。類似的，interp hide 把在這個直譯器中的一個暴露命令移動到隱藏命令的集合中。不允許安全直譯器在它自身中或它的後代中的隱藏命令和暴露命令的集合之間移動命令。

目前，隱藏命令的名字不能包含名字空間限定符，並且在你可以隱藏它之前必須首先把在一個名字空間中的命令重命令到全域性名字空中。在全域性名字空間中查詢要被 interp hide 隱藏的命令。這防止從直譯器通過使當前的名字空間不同於全域性名字空間(的方式)，來愚弄主直譯器去隱藏錯誤的命令。

感謝 CREDITS

這個機制基於由 Nathaniel Borenstein 和 Marshall Rose 實現的 Safe-Tcl 原型。

參見 SEE ALSO
load(n), safe(n), Tcl_CreateSlave(3)

關鍵字 KEYWORDS
alias, master interpreter, safe interpreter, slave interpreter

[中文版維護人]
寒蟬退士

[中文版最新更新]
2001/10/09

《中國 Linux 論壇 man 手冊頁翻譯計劃》:
http://cmpp.linuxforum.net

跋
本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃：https://github.com/man-pages-zh/manpages-zh