Os.system для вызова exe, который находится в директории, имя которой содержит пробелы

просто мой код выглядит следующим образом:

file = 'C:\\Exe\\First Version\\filename.exe'
os.system(file)

когда я запускаю эту программу, вызывается windowserror, не может найти указанный файл. Я выяснил, что проблема связана с пробелом между "Первой версией". Могу ли я найти способ обойти проблему?

PS: что, если переменная "файл" будет передана как arg в другую функцию?

Ответ 1

Помещение кавычек по пути будет работать:

file = 'C:\\Exe\\First Version\\filename.exe'
os.system('"' + file + '"')

но лучшим решением является использование модуля subprocess:

import subprocess
file = 'C:\\Exe\\First Version\\filename.exe'
subprocess.call([file])

Ответ 2

Попробуйте заключить его в двойные кавычки.

file = '"C:\\Exe\\First Version\\filename.exe"'
os.system(file)

Ответ 3

Вы можете использовать короткое имя файла с пробелами в его имени.

file = 'C:\\Exe\\FirstV~1\\filename.exe'
os.system(file)

Ответ 4

Я использовал это:

import subprocess, shlex
mycmd='"C:\\Program Files\\7-Zip\\7z" x "D:\\my archive.7z" -o"D:\\extract folder" -aou'
subprocess.run(shlex.split(mycmd))

Ответ 5

Это правда, что os.system запустит двоичный файл с пробелами в пути, заключив этот путь в кавычки. (Это должно быть довольно очевидным решением, если вы привыкли использовать терминал.) Однако само по себе это не решает более болезненную проблему с этой функцией... Как только вы это сделаете, вы можете столкнуться с проблемами, добавляя аргументы в вашу команду ! (Ааа!)

Все текущие рекомендации теперь использовать модуль subprocess вместо этой старой, нахмурившейся функции. Можно также использовать shlx для преобразования плоских строк в списки для этих функций подпроцесса. Я тоже сталкивался с проблемами или трудностями с этими методами, о которых я не буду рассказывать... Кроме того, иногда просто проще использовать os.system когда все, что вам нужно, это тонкая оболочка над оболочкой, которая неявно отображает выходные потоки. на консоли, работает синхронно и т.д. Мне бы очень хотелось, чтобы была встроенная функция для выполнения такой команды на оболочке, с абсолютно нулевым разбором, переносом, абстрагированием...

Поскольку нет встроенного без "фильтров", здесь мой патч решения для os.system. Это взято из моей библиотеки с открытым исходным кодом. Это было проверено на Windows, Mac и Ubuntu Linux. Я знаю, что это не на 100% надежно, и это больше связано с загаром, на который можно было бы надеяться, но это не так уж плохо.

Когда вы вызываете эту _system() (передавая строку для выполнения), просто _system() свой длинный путь в кавычки и включите любые аргументы, которые нужны с кавычками и без них. На первом "токене" в команде это удалит кавычки и пробелы в пути на Mac или Linux. В Windows он использует "короткое имя", фактически решая, что это в данной среде. Эта часть кода немного сложнее. В основном он использует пакетный механизм для разрешения имен и отправляет результаты обратно через stderr с целью анализа того, что вы получите в противном случае для результатов Popen() на stdout. Здесь вы также можете использовать опцию рабочего каталога и установить ее в качестве альтернативного решения.

Я думаю, что я включил весь импорт и определил, что вам нужно. Если я что-то пропустил (копирование и вставка спинов источника), дайте мне знать.

from os import system, getcwd, chdir
from subprocess import Popen, PIPE

import platform
__plat = platform.system()
IS_WINDOWS = __plat == "Windows"
IS_LINUX   = __plat == "Linux"
IS_MACOS   = __plat == "Darwin"

__SCRUB_CMD_TMPL = "{0}{1}"
__DBL_QUOTE      = '"'
__SPACE          = ' '
__ESC_SPACE      = '\\ '
if IS_WINDOWS :        
    __BATCH_RUN_AND_RETURN_CMD = ["cmd","/K"] # simply assuming cmd is on the system path... 
    __BATCH_ONE_LINER_TMPLT    = "{0} 1>&2\n" # the newline triggers execution when piped in via stdin
    __BATCH_ESCAPE_PATH_TMPLT  = 'for %A in ("{0}") do @echo %~sA' 
    from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
    __BATCH_ONE_LINER_STARTUPINFO = STARTUPINFO()
    __BATCH_ONE_LINER_STARTUPINFO.dwFlags |= STARTF_USESHOWWINDOW 

def _system( cmd, wrkDir=None ):
    if wrkDir is not None:
        initWrkDir = getcwd()
        print( 'cd "%s"' % (wrkDir,) )
        chdir( wrkDir  )
    cmd = __scrubSystemCmd( cmd )        
    print( cmd )
    system( cmd ) 
    print('')
    if wrkDir is not None: chdir( initWrkDir )

def __scrubSystemCmd( cmd ):
    """
    os.system is more convenient than the newer subprocess functions
    when the intention is to act as very thin wrapper over the shell. 
    There is just one MAJOR problem with it: 
    If the first character in the command is a quote (to escape a long path
    to the binary you are executing), then the limited (undesirable) parsing 
    built into the function can all fall apart.  So, this scrub function
    solves that...  
    """    
    if not cmd.startswith( __DBL_QUOTE ): return cmd
    cmdParts    = cmd[1:].split( __DBL_QUOTE )
    safeBinPath = _escapePath( cmdParts[0] )
    args        = __DBL_QUOTE.join( cmdParts[1:] ) # (the leading space will remain)
    return __SCRUB_CMD_TMPL.format( safeBinPath, args ) 

def _escapePath( path ):
    if not IS_WINDOWS: return path.replace(__SPACE, __ESC_SPACE)     
    return( path if __SPACE not in path else        
            __batchOneLinerOutput( __BATCH_ESCAPE_PATH_TMPLT.format(path) ) )    

def __batchOneLinerOutput( batch ):
    cmd = __BATCH_ONE_LINER_TMPLT.format( batch )
    p = Popen( __BATCH_RUN_AND_RETURN_CMD, shell=False, 
               startupinfo=__BATCH_ONE_LINER_STARTUPINFO,
               stdin=PIPE, stdout=PIPE, stderr=PIPE )    
    # pipe cmd to stdin, return stderr, minus a trailing newline
    return p.communicate( cmd )[1].rstrip()