2016-12-30 82 views
0

我想使用pgrep從命令行查找進程的pid。在外殼,這樣做是爲這樣:如何讓Tcl的exec運行一個命令,其參數用空格引用了字符串?

pgrep -u andrew -fx 'some_binary -c some_config.cfg' 

但當我嘗試這個來自TCL,像這樣:

exec pgrep -u $user -fx $cmdLine 

我得到:

p纖ep:無效選項 - 'c'

這是有道理的,因爲它看到這個:

pgrep -u andrew -fx some_binary -c some_config.cfg 

但它同樣當我添加單引號:

exec pgrep -u $user -fx '$cmdLine' 

而這也有道理,因爲單引號不是特別的Tcl的。我認爲這是考慮'some_binary的一個論點,然後是-c,然後是some_config.cfg'

我也試過:

exec pgrep -u $user -fx {$cmdLine} 

set cmd "pgrep -u $user -fx '$cmdLine'" 
eval exec $cmd 

無濟於事。

從我的閱讀中看來,Tcl 8.5+中的{*}功能可能有所幫助,但我公司的基礎架構運行的是Tcl 8.0.5。

+0

'exec'應該將它的參數按原樣傳遞給被調用的命令(即不需要進行連接和重新分割)。你是否通過'eval'執行'exec'? – Leon

回答

2

的問題是部分是'意味着什麼都沒有給Tcl,部分是你失去了控制字邊界的地方。


首先,仔細檢查,這其實工作原理:

exec pgrep -u $user -fx "some_binary -c some_config.cfg" 

或也許這(TCL採用{ ... }像Unix外殼使用單引號,但用的是可嵌套的額外好處,那就是牙套在Tcl中真的做):

exec pgrep -u $user -fx {some_binary -c some_config.cfg} 

應該是什麼工作是這樣的:

set cmdLine "some_binary -c some_config.cfg" 
exec pgrep -u $user -fx $cmdLine 

,你必須設置cmdLine正是要擁有它(通過打印如果您不確定檢查字符;重要的是變量中的值,而不是您在腳本中寫入的引用版本)。我將使用下面的set cmdLine "…"表格,但真正使用你需要的任何東西來工作。現在

,如果你將要傳遞過去的這個eval,那麼你應該使用list在你需要做的事安全的額外的引號加:

set cmdLine "some_binary -c some_config.cfg" 
set cmd [list pgrep -u $user -fx $cmdLine] 
eval exec $cmd 

list命令產生的列表,但是它使用規範形式也是一個腳本片段,它是保證缺少「驚喜」替換或單詞邊界。


如果你是一個較新版本的Tcl(特別是8.5或更高版本)的,你可以使用擴展。這被設計爲,特別是list一起工作得很好,並且在約99%的情況下襬脫了使用eval的需要。這會改變:

eval exec $cmd 

到:

exec {*}$cmd 

語義不同有點除了cmd拿着一個規範列表,當他們實際運行相同的操作。 (當處理非規範列表時,會出現差異,其中eval會做各種各樣的事情 - 想象一下破壞性的set cmd {ab [exit] cd},這是一個有效但非規範的列表 - 而擴展只是強制事物成爲列表並使用)

1

由於您使用的是舊版本,因此您必須確保eval所看到的內容將轉換爲正確引用的Tcl字符串。

單引號無效。它們不被exec使用,它們也不被傳遞。 exec利用底層的exec(3)系統調用,並且不會進行參數解釋,除非您故意使用類似於:/bin/sh -c "some-cmd some-arg"的地方,其中調用shell並將重新解釋命令行。

你需要做的是構造一個字符串,eval將解釋爲引用的Tcl字符串。您可以對這些結構使用「{part1 part2}」或「\」part1 part2 \「」。

首先,一個小的測試腳本,以驗證參數正確傳遞:

#!/bin/bash 
for i in "[email protected]"; do 
    echo $i 
done 

隨後的Tcl腳本:

#!/usr/bin/tclsh 
exec ./t.sh -u andrew -fx "some_binary -c some_config.cfg" >@ stdout 
eval exec ./t.sh -u andrew -fx "{some_binary -c some_config.cfg}" \ 
    >@ stdout 
eval exec ./t.sh -u andrew -fx "\"some_binary -c some_config.cfg\"" \ 
    >@ stdout 
# the list will be converted to a string that is already properly 
# quoted for interpretation by eval. 
set cmd [list ./t.sh -u andrew -fx "some_binary -c some_config.cfg"] 
eval exec $cmd >@ stdout 
相關問題