2014-07-03 17 views
0

在調試第三方Tcl腳本時,我遇到了一個非常奇怪的行爲:當腳本通過gunzip解壓現有文件時,Tcl文件存在'否認結果文件存在,即使它可以通過'ls'從shell中甚至通過Tcl'glob'來看到。我能夠複製在這個短(ish)腳本中的行爲:Tcl文件存在錯過生成的文件

#!/usr/bin/tclsh 

proc assert {msg asserted} { 
    if {!$asserted} { 
    puts "Assertion failed: $msg" 
    exit 1 
    } 
} 

set script_path [info script] 
set test_file [file join [file dirname $script_path] "test.tcl.gz"] 
puts "The test file is '$test_file'" 
assert "The test file does not exist" [file exists $test_file] 

set this_dir [pwd] 
set test_dir [file join $this_dir "test"] 
if {![file exist $test_dir]} { 
    file mkdir $test_dir 
} 
puts "The test directory is '$test_dir'" 
assert "'$test_dir' does not exist or is not a directory" [file isdirectory $test_dir] 

file copy $test_file $test_dir 
set working_file [file join $test_dir [file tail $test_file]] 
assert "Failed to to copy the test file to '$working_file'" [file exists $working_file] 

exec gunzip $working_file 
puts "After decompression, $test_dir contains:" 
foreach file [glob -dir $test_dir *] { 
    puts $file 
} 
set decompressed_file [file rootname $working_file] 
assert "$decompressed_file does not exist" [file exists $decompressed_file] 

我正在使用的測試文件只是腳本源的gzipped副本。它與腳本本身位於同一目錄中,如腳本所期望和檢查的那樣。下面是我運行它時得到的結果(tcl 8.5/CentOS 6.5):

bash-4.1$ ./test.tcl 
The test file is './test.tcl.gz' 
The test directory is '/home/jbolling/tmp/test' 
After decompression, /home/jbolling/tmp/test contains: 
/home/jbolling/tmp/test/test.tcl 
Assertion failed: /home/jbolling/tmp/test/test.tcl does not exist 

任何人都可以解釋這種行爲嗎?有沒有辦法說服'文件存在'來識別解壓縮的文件?

+0

我沒有收到運行腳本時斷言失敗錯誤。你可以做一個'ls -ld。 test test/test.tcl'。 –

+0

我也沒有看到斷言失敗。我的環境:Mac OS X 10.9.x,Tcl 8.5.9。 –

+0

'file exists'命令幾乎直接映射到所有Unix(包括OSX)上帶'F_OK'標誌的'access()'系統調用;由於文件鎖定模型的不同,Windows更爲複雜。你在哪個平臺上? –

回答

0

在從別人的評論中得知原始腳本爲他們工作之後,發現了一些也適用於我的變體,並且在Tcl源代碼中查找了一些變體後,我得出結論:曾經使用過file exists對象,如果目錄內容可能在調用之間改變(通常不能排除),則通過file rootname在該對象或從其派生的對象上再次使用它是不安全的。

我沒有追溯它在源代碼中發生的位置,但我的Tcl解釋器顯然緩存了某處目錄列表的結果,因爲它不僅不能識別解壓縮文件的創建,它也不會認識到刪除的原始(即gunzip也執行)。另一方面,如果我使用文字字符串路徑執行file exists測試,或者使用與以前傳遞給file exists的任何文檔完全分離的Tcl對象,則結果如預期。它也可以,如果我強制轉換爲字符串,例如通過與

assert "$decompressed_file does not exist" [file exists [string trim $decompressed_file]] 

更換

assert "$decompressed_file does not exist" [file exists $decompressed_file] 

顯然緩存行爲是特定於實現的;我的實現是CentOS 6.5的Tcl 8.5.7,但我想這種行爲可能是普遍的,至少對於Tcl 8.5.7的Unix實現(這與macosx實現不同,即使OS X是Unix)。也可能是gunzip正在做一些不尋常的事情,導致這個問題,因爲我無法通過一個簡單的mv命令複製它。無論如何,儘管我沒有完全描述這個問題,但我認爲我現在已經足夠了解這個問題了。感謝那些評論 - 你引導了我富有成效的方向。

0

該手冊爲file exists指出命令

返回1,如果文件名存在,且當前用戶有搜索 特權導致它的目錄,否則爲0。

很明顯,該文件存在,所以我懷疑你運行腳本的用戶沒有權限查看它。我必須承認,我不太清楚「通向它的目錄的搜索特權」是什麼意思。

我建議再次嘗試使用位於公開目錄中的文件。

+0

'/ a/b/c/d/file.txt'的「搜索權限」意味着你必須能夠cd到'/ a','/ a/b','/ a/b/c'中。 ..等等,一直到'/ a/b/c/d' –

+0

腳本*創建*目標文件,方法是首先將gzipped版本複製到目標目錄中,然後對其進行解壓縮。它以我的身份運行,並且我確實對其路徑中的所有目錄(我的主目錄的子目錄)具有搜索特權,我可以在該腳本外部對其進行驗證。 –

+0

此外,腳本在解壓縮之前成功使用'file exists'來測試目標目錄中是否存在.gz,因此無法通過該目錄上的搜索缺少特權來解釋問題。 –

0

小問題,但看起來像這裏可能錯字......

if {![file exist $test_dir]} { 

應該是:

if {![file exists $test_dir]} { 
+0

謝謝你的評論。 (1)您在發佈的源代碼中存在拼寫錯誤是正確的,但它實際上不會以任何方式(奇怪地)影響腳本的行爲。腳本完全按照最初發布的方式運行,並且它還可以在糾正錯字時運行,從而以完全相同的文件系統更改和打印輸出。 (2)作爲對原始問題的評論而非答案,這將更爲合適,因爲事實上它並不回答這個問題。 –