Это правда, что os.system
запустит двоичный файл с пробелами в пути, заключив этот путь в кавычки. (Это должно быть довольно очевидным решением, если вы привыкли использовать терминал.) Однако само по себе это не решает более болезненную проблему с этой функцией ... Как только вы это сделаете, вы можете запустить в трудности добавления аргументов в вашу команду ! (Ааа!)
Все текущие рекомендации теперь должны использовать модуль subprocess
вместо этой старой, не одобренной функции. Можно также использовать shlx
для преобразования плоских строк в списки для этих функций подпроцесса. Я тоже сталкивался с проблемами или трудностями в этих методах, о которых я не буду рассказывать ... Кроме того, иногда просто проще использовать os.system
, когда все, что вам нужно, это тонкая оболочка над оболочкой, которая неявно отображает выходные потоки. на консоли, работает синхронно и т. д. Я уверен, что хотелось бы иметь встроенную функцию для выполнения команды на оболочке, как это, с абсолютно 0 разбором, переносом, абстрагированием ...
Поскольку нет встроенного без «фильтров», вот мой патч решения для os.system
. Это взято из моей библиотеки с открытым исходным кодом. Это было проверено на Windows, Mac и Ubuntu Linux. Я знаю, что это не на 100% надежно, и это более сложный загар, на который можно было бы надеяться, но это не так уж плохо.
Когда вы вызываете эту _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()