subprocessでパスを開く(まとめ)

投稿者: | 2023-01-23

subprocess — サブプロセス管理 — Python 3.11.1 ドキュメント

TODO 酒井さんの動画、本を再チェック

目次

疑問

  • subprocess Popen() と subprocess run() どっちを使う?
  • ()の中身?shell=True って何?
  • subprocess を使ってフォルダを開くとき、開けるとき、開けないとき、開くけど指定してないマイドキュメントが開く?のはなぜ?

subprocess run()を使え

  • subprocess とは システムコマンド(コマンドプロンプト等)を実行できる
  • Popenでもよいが、runですべて賄える。Popenは用途が幅広い。
# いずれのやり方でもよい。同じ。1だと""に囲まれた文字がそのままコマンドとして扱われる
import subprocess

# 1.セキュリティ上、危険らしい
subprocess.run("python␣-V", shell=True)

# 2.
subprocess.run(["python", "-V"])
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
            capture_output=False, shell=False, cwd=None, timeout=None,
            check=False, encoding=None, errors=None, text=None, env=None,
            universal_newlines=None)

フォルダをきちんと開きたい

# 結論
import subprocess

subprocess.run(['explorer', str_path]) # run, 'explorer'の綴り、[ ]で囲む、pathはstr を注意

その前に

  • Windows上からフォルダパスを「コピー」しスクリプトにペーストするとパス区切りは次のいずれかになる

  • 「\(バックスラッシュ)」
  • 「¥(円マーク)」
  • 「 / (フォワードスラッシュ)」

  • この状態で変数に格納し、実行しても実行直後に“必ず” unicodeエラーになる(※)
  • SyntaxError: (unicode error) ‘unicodeescape’ codec can’t decode bytes in position 2-3: truncated \UXXXXXXXX escape
  • なぜなら「バックスラッシュ」または「円マーク」がエスケープ文字のため、直後の文字とセットで違う文字で解釈されてしまうため
    • スラッシュだといけるはずだがだめなのは?(内部でバックスラッシュにへんかんされてる?)
    • macではいいのに
    • スラッシュをwin内部で変換されているのか?
  • つまり、Windows上で自分で「コピー」したパスをスクリプト上で使うときは、必ず前もって「raw文字列」を付与しなければならないということ。
# NG(このままでは実行すら不可)
p = "C:/Users/~/Downloads"

# OK
p = r"C:/Users/~/Downloads"

2つめは次とおなじこと(要は//,\\と2つ並べることで2つめの記号を有効にしている)
p = "C://Users//~//Downloads"
p = "C:\\Users\\~\\Downloads"

いっぽう

  • 一方、sg.popup_get_folder(“~”) 経由でパスを取得し、変数に格納した状態で実行すると、直後に(※)のエラーは出ない!!
  • そのまま処理が進み、指定されたパスが開くと思いきや、なぜか指定してない「マイドキュメント」が開いたりする、VSCODEだとそもそも反応しない(エラーもなし)。
  • そのとき、sg.popupで取得したパスは「’C:/Users//Downloads’」。
  • しかも、取得済みの変数には raw文字列 は付与できないはず
  • 原因は、raw文字列を付与できない状態の無効なパス(「’C:/Users/~/Downloads’」)を無理くり開こうとしたためである。
  • ここでのパス区切りは「/(スラッシュ)」。

結論(対策と考え方)

  1. sg.popup_get_file等で変数に格納されたパスに、変数のまま「raw文字列」を付与することはできない(たぶん。あったら知りたい)
  2. 1 の変数のパス区切り「/(スラッシュ)または¥」(=エスケープ文字)を「\\(2つのバックスラッシュ)」に置換する。記載の仕方は以下。変にエスケープだから….「”//”, “\\\\”」で replace しようとするとはまる。

よって、上記の条件であっても、次のスクリプトであれば subprocessから指定フォルダを開くことができる

結果スクリプト

import PySimpleGUI as sg
import subprocess

p1 = sg.popup_get_folder("select folder? ")
p2 = p1.replace("/", "\\")
return = subprocess.run(["explorer", p2])
カテゴリー: OS