92571


以下のようなバッチファイルがあります。  
このバッチファイルを使用せずに、Pythonから同等の処理をしてtest.exeを実行したいです。

**run.bat**

exeファイル実行時には、コマンドライン引数を使用します。

[code]

    SETLOCAL
    SET PATH=%PATH%;..\..\samples\external\opencv\bin;..\..\bin;
    test.exe --view_mode=1
    
[/code]

以下が、Pythonで分かる部分だけ記述したものになります。

**test.py**

[code]

    from os import path
    import subprocess
    
    #exeファイルを実行する部分(コマンドライン引数を呼び出す方法があっているか分かりません。)
    exePath = path.join(path.dirname(__file__), 'test.exe')
    subprocess.Popen([exePath,"--view_mode=1"])
    
[/code]

SET PATHがどのようなことをしているのか理解できていないため、Pythonでの記述方法が分かりません。どうしたら同等の処理を行えますか？


CC BY-SA 4.0
2022-12-04T01:19:24.510
92563
2022-12-05T09:33:54.667
36446
question
python windows batch-file
Windowsバッチファイルの"SET PATH"と同等の処理をPythonから実行したい


一般論として

  * 環境変数 `PATH` はプロセスを起動する際に実行ファイルを検索する対象を示します。
  * 環境変数は子プロセスに引き継がれます。

この２つから、２つの効果が得られます。

  * `test.exe` を起動する際に環境変数 `PATH` の中から検索されます。
  * `test.exe` が更に子プロセスを起動する際、（`test.exe`が明示的に排除しなければ）環境変数 `PATH` の中から検索されます。

質問文ではこの２つの効果のうちどちらを期待するものかわかりませんでした。

前者を期待するのであれば、`test.exe` がどのディレクトリに配置されているのか知っているならば、

>
[code]

>     exePath = path.join(path.dirname(__file__), 'test.exe')
>  
[/code]

で十分です。

後者を期待するのであれば、
[`subprocess.Popen()`](https://docs.python.org/ja/3/library/subprocess.html#popen-
constructor) の `env` 引数に渡すことができます。

* * *

極まれに、環境変数 `PATH` が設定されていないと `test.exe` 自身が正常動作できないことがあります。具体的には `test.exe`
が[DLLを読み込む際にも 環境変数 `PATH` から検索することができ](https://learn.microsoft.com/ja-
jp/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-
for-desktop-applications)、それに頼っている場合です。このような場合も`subprocess.Popen()` の `env`
引数を設定する必要があります。


CC BY-SA 4.0
2022-12-04T01:35:56.037
92564
2022-12-04T01:35:56.037
4236
92563
answer


プログラム起動するだけなら直接起動可能

[code]

    import subprocess
    from pathlib import Path
    
    def execpg():
        for p in ('../../samples/external/opencv/bin', '../../bin'):
            prog = Path(p)/ 'test.exe'
            if prog.exists():
                break
        else:
            print('実行ファイルが見つからない')
            return
    
        proc = subprocess.Popen([prog, '--view_mode=1'])
    
    execpg()
    
[/code]

* * *

> Pythonから同等の処理を

環境変数を加工する必要がある場合 …

とりあえず環境変数 PATHについてざっくりと, あとは自分で調べてみてください

  * 環境変数はプロセスごとに存在する, サププロセス起動すると親プロセスの環境を引き継ぐ(新しい環境変数)
  * PATHは, プログラム起動の際に プログラムを探索するパスのリスト
  * なので探索リストが相対パスだと (たいてい)意味がない

カレントディレクトリ相対だと, ディレクトリー移動すると PATHは意味を成さないので注意のこと

環境変数 PATH の設定  
(カレント相対になってる対処も含む)

(pathlib 使ってるけど `os.path` でも可能なはず, 好みで)

[code]

    import os
    from pathlib import Path
    
    npath = os.pathsep.join(str(Path(p).resolve())
                for p in ('../../samples/external/opencv/bin', '../../bin'))
    
    print(os.environ['PATH'])
    os.environ['PATH'] += os.pathsep + npath
    print(os.environ['PATH'])
    
[/code]

(追記)  
`resolve()` のところは `absolute()` でも OK。  
カレントからの相対でなければ  
(以下は colabでの確認, なので Windowsとは異なるが)

[code]

    paths = os.pathsep.join(str(Path(p).absolute())
                for p in ('../../samples/external/opencv/bin', '../../bin'))
    print(paths)
    
    # /content/../../samples/external/opencv/bin:/content/../../bin
    
[/code]


CC BY-SA 4.0
2022-12-04T08:07:33.783
92569
2022-12-05T09:33:54.667
2022-12-05T09:33:54.667
43025
43025
92563
answer


ディレクトリ＆ファイル構成が以前の質問
[Pythonから.batファイルや.vbsファイルを実行したい](https://ja.stackoverflow.com/q/92500/26370)
と同じで、Pythonスクリプトとtest.exeが同じディレクトリにあると仮定すると、コメントで紹介したこれらの記事を適用して、以下のように出来るでしょう。  
[Python のサブプロセスで環境変数を扱う方法](https://hawksnowlog.blogspot.com/2021/06/python-
subproces-with-environment-variables.html)  
[Pythonのサブプロセスを使ったメモ](https://qiita.com/bonk/items/d2f5631683e52e1c39e7)

[code]

    from os import path
    import subprocess
    
    import os
    savedir = os.getcwd() #### 起動時のカレントディレクトリ情報を保存し、必要ならば後で戻す。
    #### カレントディレクトリをPythonスクリプトとtest.exeのあるディレクトリに移動する
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    
    #### 環境変数をコピー(SETLOCALに相当)し、OpenCV等の必要なソフトウェアのディレクトリをPATHに追加する
    subenv = os.environ.copy()
    subenv["PATH"] = subenv['PATH'] + r';..\..\samples\external\opencv\bin;..\..\bin;'
    
    #exeファイルを実行する部分(コマンドライン引数を呼び出す方法があっているか分かりません。)
    exePath = path.join(path.dirname(__file__), 'test.exe')
    subprocess.Popen([exePath,"--view_mode=1"], env=subenv)  #### 起動時のパラメータに変更した環境変数を指定
    
[/code]


CC BY-SA 4.0
2022-12-04T09:10:34.433
92571
2022-12-04T09:10:34.433
26370
92563
answer


まず、ご指定のバッチファイルは以下とほぼ等価です。

[code]

    from os import environ
    import subprocess
    environ['PATH'] = environ['PATH'] + ';..\\..\\samples\\external\\opencv\\bin;..\\..\\bin;'
    result = subprocess.run(['test.exe', '--view_mode=1'], shell=True)
    
[/code]

ご質問の`SET PATH=...`のSETコマンドについては、以下を御覧ください。  
<https://learn.microsoft.com/ja-jp/windows-server/administration/windows-
commands/set_1>  
簡単に言えば環境変数を表示、設定、削除する内部コマンドです。

環境変数については以下を御覧ください。  
<https://learn.microsoft.com/ja-jp/windows/win32/procthread/environment-
variables>  
簡単に言えばシステム共通の方式でアクセスできる各プロセス固有の変数です。

PATHについては、以下に少し記述があります(以下はPATHコマンドの説明ですが、PATH環境変数についての説明が多少あります)  
<https://learn.microsoft.com/ja-jp/windows-server/administration/windows-
commands/path>  
簡単に言えば主に実行可能ファイルを検索する場所や順番を指定するものです。

※Windowsの環境変数はcmd.exeの制約や環境変数領域の制約などにより、2048バイトを超えるところで不思議な動作をすることがあります。


CC BY-SA 4.0
2022-12-05T01:53:16.557
92582
2022-12-05T01:53:16.557
54957
92563
answer