Если у удаленного пользователя есть оболочка POSIX, это должно работать:
def shell_escape(arg):
return "'%s'" % (arg.replace(r"'", r"'\''"), )
Почему это работает?
Одиночные кавычки оболочки POSIX определяются как:
Заключение символов в одинарные кавычки ('') должно сохранять буквальное значение каждого символа в одинарных кавычках. Одиночная кавычка не может встречаться в одинарных кавычках.
Идея в том, что вы заключаете строку в одинарные кавычки. Это само по себе почти достаточно хорошо - каждый символ, кроме одной кавычки, будет интерпретироваться буквально. Для одинарных кавычек вы выпадаете из строки в одинарных кавычках (первая '
), добавляете одинарные кавычки (\'
) и затем возобновляете строку в одинарных кавычках (последняя '
).
С чем это работает?
Это должно работать для любой оболочки POSIX. Я проверил это с тире и Баш. * Solaris 5.10 /bin/sh
(который, я считаю, не совместим с POSIX, и я не смог найти спецификацию для него) также, похоже, работает.
Для произвольных удаленных хостов я считаю, что это невозможно. Я думаю, что ssh
выполнит вашу команду с любой оболочкой удаленного пользователя (как настроено в /etc/passwd
или эквивалентной). Если удаленный пользователь может работать, скажем, /usr/bin/python
или git-shell
или что-то в этом роде, любая схема цитирования может не только столкнуться с несоответствиями между оболочками, но и выполнение вашей команды также может привести к сбою.
csh / tcsh
Чуть более проблематична вероятность того, что удаленный пользователь может запустить tcsh
, так как некоторые люди действительно запускают это в дикой природе и могут ожидать, что exec_command
парамико будет работать. (Пользователи /usr/bin/python
в качестве оболочки, вероятно, не имеют таких ожиданий ...)
tcsh, кажется, в основном работает. Тем не менее, я не могу найти способ процитировать новую строку, чтобы он был счастлив. Включение новой строки в строку в одинарных кавычках делает tcsh несчастным:
$ tcsh -c $'echo \'foo\nbar\''
Unmatched '.
Unmatched '.
Кроме новых строк, все, что я пробовал, похоже, работает с tcsh (включая одинарные, двойные, обратные слэши, встроенные табуляции, звездочки, ...).
Проверка оболочки на выход
Если у вас есть схема побега, вот некоторые вещи, с которыми вы можете проверить:
- Escape-последовательности (
\n
, \t
, ...)
- Котировки (
'
, "
, \
)
- Глобус символов (
*
, ?
, []
и т. Д.)
- Работа контроля и трубопроводов (
|
, &
, ||
, &&
, ...)
- Newlines
Новые строки заслуживают особого внимания. Решение re.escape
не обрабатывает это право - оно экранирует любой не алфавитно-цифровой символ, а оболочка POSIX считает экранированную новую строку (т. Е. В Python двухбуквенная строка "\\\n"
) быть нулем символов, а не один символ новой строки. Я думаю, re.escape
правильно обрабатывает все другие случаи, хотя меня пугает использование чего-то, предназначенного для регулярных выражений, для экранирования оболочки. Это может сработать, но я бы беспокоился о тонком случае в re.escape
или правилах экранирования оболочки (таких как переводы строк) или возможных будущих изменениях в API.
Вы также должны знать, что escape-последовательности могут обрабатываться на разных этапах, что усложняет тестирование - вам важно только то, что оболочка передает программе, а не то, что программа делает. Использование printf "%s\n" escaped-string-to-test
, вероятно, лучшая ставка. echo
работает на удивление плохо: в dash обратная косая черта встроенных процессов echo
экранируется как \n
. Использование /bin/echo
обычно безопасно, но на машине с Solaris 5.10, на которой я тестировал, оно также обрабатывает последовательности вроде \n
.