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’」)を無理くり開こうとしたためである。
- ここでのパス区切りは「/(スラッシュ)」。
結論(対策と考え方)
- sg.popup_get_file等で変数に格納されたパスに、変数のまま「raw文字列」を付与することはできない(たぶん。あったら知りたい)
- 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])