Ответ 1
"Проблема" с expr
заключается в том, что она реализует свой собственный "мини-язык", который включает, среди прочего, замену переменных (заменяя те $a
-s своими значениями) и замену команд (заменяя те [command ...]
вещи с результатами работы command
s), поэтому в основном процесс оценки expr $a + $b
выглядит следующим образом:
- Интерпретатор Tcl анализирует четыре слова -—
expr
,$a
,+
и$b
из исходной строки. Поскольку два из этих слов начинаются с$
, замена переменных происходит так, что на самом деле будутexpr
,1
,+
и2
. - Как обычно, первое слово считается именем команды, а другие являются аргументом для него, поэтому интерпретатор Tcl ищет команду с именем
expr
и выполняет ее, передавая ей три аргумента:1
,+
и2
. - Реализация if
expr
затем объединяет все переданные ей аргументы, интерпретируя их как строки, получая строку1 + 2
. - Затем эта строка снова обрабатывается — на этот раз механизмом
expr
, согласно его собственным правилам, которые включают подстановки переменных и команд, как уже упоминалось.
Что следует:
- Если вы привязываете свои
expr
эссенции, как вexpr {$a + $b}
, группировка, предоставляемая этими фигурными фигурными скобками, запрещает интерпретацию интерпретатором Tcl 1 script, который должен быть проанализирован самимexpr
. Это означает, что в нашем игрушечном примере командаexpr
увидит ровно один аргумент$a + $b
и сама выполнит подстановки. -
"Двойной парсинг", описанный выше, может привести к проблемам безопасности.
Например, в следующем коде
set a {[exec echo rm -rf $::env(HOME)]} set b 2 expr $a + $b
Команда
expr
сама проанализирует строку[exec echo rm -rf $::env(HOME)] + 2
. Его оценка потерпит неудачу, но к тому времени содержимое вашего домашнего каталога, предположительно, исчезнет. (Обратите внимание, что вид Tcler помещенecho
передrm
в более позднем редактировании моего ответа, пытаясь сохранить шейки случайных копий, поэтому команда в письменном виде не вызоветrm
, но если вы удалитеecho
от него, будет.) - Двойной синтаксический анализ запрещает определенные оптимизации, которые может использовать механизм Tcl при работе с вызовами
expr
.
1 Ну, почти; последовательности "backslash + newline" все еще обрабатываются даже внутри {...}
блоков.