web-dev-qa-db-ja.com

名前に空白が含まれているディレクトリにあるexeを呼び出すos.system

私のコードは単純に次のとおりです。

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

このプログラムを実行すると、Windowsエラーが発生します:can't find the file specified.

「最初のバージョン」の途中の空白に問題があることがわかりました。問題を回避する方法をどのように見つけることができますか?

追伸:変数「ファイル」が引数として別の関数に渡されている場合はどうなりますか?

17
Synapse

パスを引用符で囲むと機能します。

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

しかし、より良い解決策は、代わりにsubprocessモジュールを使用することです。

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

私はこれを使用しました:

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))
2
abicorios

二重引用符で囲んでみてください。

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

_os.system_は、パスを引用符で囲むことにより、パスにスペースがあるバイナリを起動することは事実です。 (端末の使用に慣れている場合、これはかなり明白な解決策になるはずです。)ただし、それだけでは、この関数のより厄介な問題は解決されません...一度実行すると、コマンドに引数を追加すると問題が発生する可能性があります! (ああ!)

現在のすべての推奨事項は、この古い関数の代わりにsubprocessモジュールを使用することです。 shlxを使用して、フラット文字列をこれらのサブプロセス関数のリストに変換することもできます。これらのメソッドでも問題や問題が発生しましたが、これについては説明しません...また、シェルの薄いラッパーだけが必要な場合は、_os.system_を使用する方が簡単な場合があります。コンソールでストリームを出力し、同期的に動作するなど。このような解析、ラッピング、抽象化を絶対に行わずに、シェルでコマンドを実行する組み込み関数があればいいのにと思います.。

「フィルター」のない組み込みはないので、これが_os.system_のソリューションパッチです。これは私のオープンソースライブラリから削除されました。これは、Windows、Mac、およびUbuntuLinuxでテストされています。私はそれが100%絶対確実ではないことを知っています、そしてそれは人が望むであろうより複雑な日焼けです、しかしそれはそれほど悪くはありません。

この_system()ラッパーを呼び出す(実行する文字列を渡す)ときは、長いパスを引用符で囲み、引用符の有無にかかわらず必要な引数も含めます。コマンドの最初の「トークン」で、MacまたはLinuxのパスにある引用符とエスケープスペースが削除されます。 Windowsでは、特定の環境にあるものを実際に解決することにより、「短い名前」を使用します。コードのその部分は少し注意が必要です。基本的に、名前解決にバッチメカニズムを使用し、stdoutのPopen()結果に対して得られる結果を解析する目的で、結果をstderrに送り返します。ここで作業ディレクトリオプションを使用して、代替ソリューションとして最初に設定することもできます。

私はすべてのインポートを含め、あなたが必要とすることを定義していると思います。 (ソースのスピネットのコピーと貼り付け)を見逃した場合は、お知らせください。

_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()  
_
1
BuvinJ

名前にスペースが含まれているファイルの 短縮名 を使用できます。

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