Вызов системной команды и параметров в виде списка

subprocess.call(f'команда строчкой', shell=True)

Наткнулся на метод subprocess, команда в котором была указана в виде списка.

К примеру,

subprocess.call(['ffmpeg','-i','file.mp4'], shell=True)

Попробовал, выдало ошибку. К тому же, мне показалось это неудобным, так как параметр и значения были отдельны друг от друга. Как через subprocess.call правильно указать, что команда передается в списке, а не строкой?

И возможно ли:

  1. Передать команде параметр и его значение, как единый элемент в списке?
  2. Возможно ли передать список, значения в котором будут в виде строки? То есть, одну большую строку произвольно разбить на список и передать его команде.

Ответы (1 шт):

Автор решения: gord1402

Преобразованием списка в строку в subproccess занимается list2cmdline (Это функция выполняется над списком внутри popen её не нужно применять самому. Данный код приведён для демонстрации, его не нужно использовать в своём коде.):

def list2cmdline(seq):
    """
    Translate a sequence of arguments into a command line
    string, using the same rules as the MS C runtime:

    1) Arguments are delimited by white space, which is either a
       space or a tab.

    2) A string surrounded by double quotation marks is
       interpreted as a single argument, regardless of white space
       contained within.  A quoted string can be embedded in an
       argument.

    3) A double quotation mark preceded by a backslash is
       interpreted as a literal double quotation mark.

    4) Backslashes are interpreted literally, unless they
       immediately precede a double quotation mark.

    5) If backslashes immediately precede a double quotation mark,
       every pair of backslashes is interpreted as a literal
       backslash.  If the number of backslashes is odd, the last
       backslash escapes the next double quotation mark as
       described in rule 3.
    """

    # See
    # http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
    # or search http://msdn.microsoft.com for
    # "Parsing C++ Command-Line Arguments"
    result = []
    needquote = False
    for arg in map(os.fsdecode, seq):
        bs_buf = []

        # Add a space to separate this argument from the others
        if result:
            result.append(' ')

        needquote = (" " in arg) or ("\t" in arg) or not arg
        if needquote:
            result.append('"')

        for c in arg:
            if c == '\\':
                # Don't know if we need to double yet.
                bs_buf.append(c)
            elif c == '"':
                # Double backslashes.
                result.append('\\' * len(bs_buf)*2)
                bs_buf = []
                result.append('\\"')
            else:
                # Normal char
                if bs_buf:
                    result.extend(bs_buf)
                    bs_buf = []
                result.append(c)

        # Add remaining backslashes, if any.
        if bs_buf:
            result.extend(bs_buf)

        if needquote:
            result.extend(bs_buf)
            result.append('"')

    return ''.join(result)
  1. Если в элементе будет пробельный символ, то он окружится кавычками и будет рассмотрен как 1 аргумент.
  2. Только если разбивать строчку по пробельным символам
→ Ссылка