26

我的代码如下:

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

当我运行这个程序时,会出现一个 Windows 错误:can't find the file specified.

我发现问题与“第一版”中间的空格有关。我怎样才能找到一种方法来规避这个问题?

PS:如果变量“文件”作为参数传递给另一个函数怎么办?

4

5 回答 5

31

在路径周围加上引号将起作用:

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

但更好的解决方案是改用该subprocess模块:

import subprocess
file = 'C:\\Exe\\First Version\\filename.exe'
subprocess.call([file])
于 2011-08-08T02:35:13.650 回答
7

我用这个:

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))
于 2018-02-18T22:19:33.377 回答
3

尝试用双引号括起来。

file = '"C:\\Exe\\First Version\\filename.exe"'
os.system(file)
于 2011-08-08T02:21:53.650 回答
2

确实,os.system将启动一个在路径中有空格的二进制文件,方法是将该路径包含在引号中。(如果您习惯使用终端,这应该是一个非常明显的解决方案。)然而,它本身并不能解决这个功能更痛苦的问题......一旦你这样做了,你可能会遇到麻烦添加你的命令的参数!(啊!)

当前的所有建议都是现在使用该subprocess模块,而不是使用这个旧的、不受欢迎的功能。还可以使用shlx将平面字符串转换为这些子流程函数的列表。我也遇到了这些方法的问题或痛苦,我不会漫无边际地谈论......此外,os.system当你想要的只是外壳上的薄包装器时,它有时会更容易使用,它会隐式显示输出流控制台,同步工作等。我当然希望有一个内置函数可以像这样在 shell 上执行命令,绝对 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()  

更新

我最近发现了一个更好的 Windows 上下文技巧。您不需要任何转换为​​短文件名或空格的转义序列。你需要做的就是通过检查命令中的第一个字符是否是双引号来阻止 Python 源代码。好吧,在 Windows cmd / Batch 上,您可以在任何命令前加上 an@以指示不要“回显”该行。所以,如果你只是在你的命令前面加上它,将不再有前导引号!您可能也不希望命令回显,因此无论如何它都是对自身的改进。

本质上,将__scrubSystemCmd上面替换为以下内容。如果你愿意,你可以删除所有获得短文件名的代码(这就像我最初发布的代码的一半!)......

if IS_WINDOWS: 
    ...
    __NO_ECHO_PREFIX = "@"

def __scrubSystemCmd( cmd ):
    if IS_WINDOWS: 
        if not cmd.startswith( __NO_ECHO_PREFIX ): 
            return __NO_ECHO_PREFIX + cmd
    elif 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 ) 
于 2019-01-26T16:37:43.443 回答
0

您可以使用名称中包含空格的文件的名称。

file = 'C:\\Exe\\FirstV~1\\filename.exe'
os.system(file)
于 2011-08-08T02:25:48.387 回答