Во время отладки стороннего Tcl-скрипта я столкнулся с очень странным поведением: когда скрипт распаковывает существующий файл с помощью gunzip, Tcl 'file exists' отрицает существование файла результата, даже если он виден через 'ls' из shell и даже через Tcl 'glob'. Мне удалось воспроизвести поведение в этом коротком (ish) скрипте:
#!/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]
Тестовый файл, который я использую, представляет собой просто сжатую копию исходного кода скрипта. Он находится в том же каталоге, что и сам сценарий, как ожидает и проверяет сценарий. Вот что я получаю, когда запускаю его (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
Кто-нибудь может объяснить такое поведение? Есть ли способ убедить, что «файл существует», чтобы распознать распакованный файл?
3 ответа
Узнав из комментариев других, что исходный сценарий работал на них, обнаружив некоторые варианты, которые также работали для меня, и ковыряясь в исходном коде Tcl, я пришел к выводу: однажды использовав file exists
на объект, небезопасно использовать его снова на этом объекте или на объекте, производном от него через file rootname
, если содержимое каталога могло измениться между вызовами (что часто нельзя исключать).
Я не проследил, где это происходит в источнике, но мой интерпретатор Tcl явно где-то кэширует результаты списка каталогов, поскольку он не только не распознает создание распакованного файла, но также не распознает удаление оригинала (этот же архиватор также выполняет). С другой стороны, если я выполняю тест file exists
, используя буквальный строковый путь или используя объект Tcl, который достаточно отделен от любого ранее переданного в file exists
, то результат будет таким, как ожидалось. Это также работает, если я принудительно преобразовываю в строку, например, заменяя
assert "$decompressed_file does not exist" [file exists $decompressed_file]
С участием
assert "$decompressed_file does not exist" [file exists [string trim $decompressed_file]]
Очевидно, поведение кэширования зависит от реализации; моя реализация - Tcl 8.5.7 из CentOS 6.5, но я полагаю, что поведение, вероятно, является общим, по крайней мере, для реализации Tcl 8.5.7 для Unix (которая отличается от реализации macosx, хотя OS X - это Unix). Также может быть, что gunzip делает что-то необычное, что усугубляет проблему, потому что мне не удалось продублировать это с помощью exec
простой команды mv.
В любом случае, хотя я не полностью охарактеризовал проблему, я думаю, что теперь я понимаю ее достаточно хорошо, чтобы быть уверенным в том, что можно обойти проблему. Спасибо тем, кто прокомментировал - вы направили меня в плодотворном направлении.
Незначительная проблема, но здесь похоже на возможную опечатку ...
if {![file exist $test_dir]} {
Должно быть:
if {![file exists $test_dir]} {
В руководстве для файл существует указано, что команда
Возвращает 1, если имя файла существует и текущий пользователь имеет права поиска для каталогов, ведущих к нему, 0 в противном случае.
Очевидно, что файл существует, поэтому я подозреваю, что пользователь, у которого вы запускаете скрипт, не имеет разрешения на его просмотр. Должен признаться, я не совсем уверен, что означает «привилегия поиска для каталогов, ведущих к нему».
Я предлагаю повторить попытку с файлом, находящимся в общедоступном каталоге.
/a/b/c/d/file.txt
означают, что вы должны иметь возможность перейти в /a
, /a/b
, /a/b/c
... и так далее, вплоть до /a/b/c/d
file exists
для проверки существования .gz в целевом каталоге перед распаковкой, поэтому проблема не может быть объяснена отсутствием прав поиска в этом каталоге.
Похожие вопросы
Новые вопросы
tcl
Инструмент Command Language был изобретен Джоном Оустерхаутом как способ облегчить написание небольших языков для настройки инструментов EDA, но он далеко вышел за эти скромные начала и стал общим языком сценариев со встроенными асинхронными вводами-выводами и Unicode-строками. поддерживая парадигмы, такие как объектно-ориентированное программирование и сопрограммы.
ls -ld . test test/test.tcl
.file exists
в значительной степени соответствует системному вызовуaccess()
с флагомF_OK
во всех Unix, включая OSX; Windows сложнее из-за различий в моделях блокировки файлов. На какой платформе вы находитесь?