Ruby %x разветвляется на 64-разрядный Linux, но не на 32-разрядный, и только с определенным синтаксисом
Вопрос
Вот немного кода Ruby:
puts %x{ pstree #{$$} } # never forks
puts %x{ pstree '#{$$}' } # forks on amd64 only
На 32-разрядном Ubuntu Dapper я получаю следующий вывод:
t.rb---pstree
t.rb---pstree
Что для меня имеет смысл.Но на 64-битной Ubuntu Hardy я получаю следующее:
t.rb---sh---pstree
t.rb---pstree
Здесь показано, что Ruby разветвляется перед выполнением только в одном из случаев.Когда я помещаю код в файл и запускаю его под strace -fF, оказывается, что на 64-разрядном Hardy он вызывает clone()
(например fork()
) до того , как execve()
, тогда как на 32-битном Dapper он ничего подобного не делает.
Мои версии Ruby следующие:
ruby 1.8.4 (2005-12-24) [i486-linux]
ruby 1.8.6 (2007-09-24 patchlevel 111) [x86_64-linux]
Мне следовало бы попробовать чаще смешивать и подбирать интерпретаторы, операционные системы и размеры слов, но прямо сейчас это непросто, поскольку я не администрирую эти машины.Может быть, кто-нибудь из вас сможет сказать мне, в чем вообще разница между этими командами в 64-разрядной системе, не говоря уже о том, почему они работают одинаково в 32-разрядной.
Решение
Ruby выполняет расширение оболочки, когда %x используется с одним аргументом (как это делаете вы).
Вот мое предположение относительно того, что происходит:
Ruby сканирует команду, чтобы определить, есть ли какие-либо специальные символы, которые привели бы к необходимости выполнения расширения оболочки, если это так, он вызывает оболочку для этого.Во втором примере одинарных кавычек достаточно, чтобы заставить Ruby захотеть вызвать оболочку для выполнения расширения, отсюда и форк.В первом примере Ruby может определить, что расширение оболочки не требуется, поскольку команда не содержит специальных символов (после расширения переменной), следовательно, форка нет.Разница между двумя версиями, вероятно, связана с внутренним изменением в том, как ruby пытается определить, требуется ли расширение оболочки.Я получаю форк для второго примера на ruby 1.8.5 на 32-разрядной машине.
[ПРАВИТЬ]
Хорошо, я взглянул на исходный код ruby 1.8.4 и 1.8.6, и обе версии используют одни и те же критерии для определения того, следует ли вызывать оболочку для выполнения расширения оболочки, если в командной строке существует любой из следующих символов, оболочка будет вызвана при предоставлении одного аргумента для %x:
*?{}[]<>()~&|\\$;'`"\n
Ruby фактически вызывает оболочку в обоих случаях (в примере, который содержит кавычки), причина, по которой вы видите разные выходные данные из pstree
это связано с различиями в sh
команда на разных машинах, одна вызывает fork
, другой - нет.Чтобы убедиться в этом самостоятельно, запустите эту команду на обеих машинах:
/bin/sh -c "pstree $$"
Это команда, которую Ruby использует для выполнения pstree
в примере с кавычками на обеих машинах.Ты должен увидеть bash---pstree
на 32-разрядной машине и bash---sh---pstree
с другой стороны.
Итак, теперь мне любопытно, что заставило вас обнаружить это различие и вызывает ли оно проблему?
Другие советы
Я прошел через эту ситуацию, разработав асинхронную работу процессора, которая имеет ряд подпроцессов (fork), и это произошло, когда мастер был на переднем плане и получил SIGINT.
Я бегу:выводит "результат равен %(monster-delayed-job)".
и на выходе был только:"в результате получается "
- Да, я использую СИГИНТ "ловушки" в главном
Андре