Вопрос

При использовании os.system() часто необходимо экранировать имена файлов и другие аргументы, передаваемые командам в качестве параметров.Как я могу это сделать?Предпочтительно что-то, что работало бы на нескольких операционных системах / оболочках, но, в частности, для bash.

В настоящее время я делаю следующее, но уверен, что для этого должна быть библиотечная функция или, по крайней мере, более элегантный / надежный / эффективный вариант:

def sh_escape(s):
   return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")

os.system("cat %s | grep something | sort > %s" 
          % (sh_escape(in_filename), 
             sh_escape(out_filename)))

Редактировать: Я принял простой ответ об использовании кавычек, не знаю, почему я об этом не подумал;Я думаю, потому, что я пришел из Windows, где "и " ведут себя немного по-другому.

Что касается безопасности, я понимаю проблему, но в данном случае меня интересует быстрое и простое решение, которое предоставляет os.system(), а источник строк либо не сгенерирован пользователем, либо, по крайней мере, введен доверенным пользователем (мной).

Это было полезно?

Решение

Это то, что я использую:

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

Оболочка всегда будет принимать заключенное в кавычки имя файла и удалять окружающие кавычки перед передачей его рассматриваемой программе. В частности, это позволяет избежать проблем с именами файлов, которые содержат пробелы или любой другой тип неприятного метасимвола оболочки.

Обновление . Если вы используете Python 3.3 или более позднюю версию, используйте shlex.quote вместо собственного.

Другие советы

shlex.quote () делает то, что вы хотите, начиная с Python 3.

(Используйте pipe.quote для поддержки как Python 2, так и Python 3)

Возможно, у вас есть конкретная причина для использования os.system () . Но если нет, то вам, вероятно, следует использовать модуль subprocess . Вы можете указать трубы напрямую и избегать использования оболочки.

Ниже приводится PEP324 :

Replacing shell pipe line
-------------------------

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

Может быть, subprocess.list2cmdline лучше?

Обратите внимание, что pipe.quote на самом деле не работает в Python 2.5 и Python 3.1 и не безопасен в использовании - он не обрабатывает аргументы нулевой длины.

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

См. выпуск Python 7476 ; это было исправлено в Python 2.6 и 3.2 и новее.

Я считаю, что os.system просто вызывает любую командную оболочку, настроенную для пользователя, поэтому я не думаю, что вы можете сделать это независимым от платформы способом.Моей командной оболочкой может быть что угодно из bash, emacs, ruby или даже quake3.Некоторые из этих программ не ожидают того типа аргументов, которые вы им передаете, и даже если бы они это сделали, нет никакой гарантии, что они выполнят экранирование таким же образом.

УВЕДОМЛЕНИЕ:Это ответ для Python 2.7.x.

В соответствии с Источник, pipes.quote() это способ "Надежно заключать строку в кавычки в качестве единственного аргумента для /мусорное ведро/sh".(Хотя это и так устарел с версии 2.7 и, наконец, публично представлен в Python 3.3 как shlex.quote() функция.)

Вкл . другая рука, subprocess.list2cmdline() это способ "Преобразуйте последовательность аргументов в строку командной строки, используя те же правила, что и Среда выполнения MS C".

Вот он, независимый от платформы способ заключения строк в кавычки для командной строки.

import sys
mswindows = (sys.platform == "win32")

if mswindows:
    from subprocess import list2cmdline
    quote_args = list2cmdline
else:
    # POSIX
    from pipes import quote

    def quote_args(seq):
        return ' '.join(quote(arg) for arg in seq)

Использование:

# Quote a single argument
print quote_args(['my argument'])

# Quote multiple arguments
my_args = ['This', 'is', 'my arguments']
print quote_args(my_args)

Используемая мной функция:

def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\\', '\\\\')
        .replace('"', '\\"')
        .replace('

то есть: я всегда заключаю аргумент в двойные кавычки, а затем заключаю в обратный слэш только те символы, которые заключены в двойные кавычки.

, '\\

то есть: я всегда заключаю аргумент в двойные кавычки, а затем заключаю в обратный слэш только те символы, которые заключены в двойные кавычки.

) .replace('`', '\\`') )

то есть: я всегда заключаю аргумент в двойные кавычки, а затем заключаю в обратный слэш только те символы, которые заключены в двойные кавычки.

Если вы используете системную команду, я бы попытался внести в белый список то, что входит в вызов os.system () .. Например ..

clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))

Модуль подпроцесса - лучший вариант, и я бы порекомендовал стараться по возможности избегать использования чего-либо вроде os.system / subprocess.

Реальный ответ таков: не используйте в первую очередь os.system () . Вместо этого используйте subprocess.call и предоставить неэкранированные аргументы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top