[解決済み] Python のピット: os.system() はスペースを含む長いパスを実行し、二重引用符のパラメーターにはバグがあります

Python コードで DOS コマンドを実行するには、os ライブラリの os.system() 関数を使用できます。使い方はとても簡単ですが、os.system は出力結果を変数に返さないことに注意してください。今日、私はバグを発見しました: DOS コマンド ラインに二重引用符のパスと二重引用符のパラメーターがある場合、os.system() 操作の結果は常に次のように表示されます: 「XXX (パス名) は内部コマンドまたは外部コマンドではありません。実行可能プログラムやバッチ ファイルでもありません。」

ffmpeg を使用して動画を変換する Python バッチ コードを作成しました。まず、ffmpeg のパスを定義します。

ffmpeg_path = r'D:\Program Files\ffmpeg\bin\ffmpeg.exe'

os.system(ffmpeg_path) を実行すると、エラーが報告されます。これは、開始時によく遭遇する現象です。

3961c0b4d3d64ca4845a3e558f3ef3c3.png

明らかに、パス名の Program Files にはスペースが含まれており、DOS ではスペースを含むパスには二重引用符が必要です。そのため、os.system() を正しく実行するには、次のようにコードを変更する必要があります。

ffmpeg_path = r'"D:\Program Files\ffmpeg\bin\ffmpeg.exe"'

これは、今日私が話したいポイントではありません。

ffmpeg は、ts 形式の m3u8 ファイルを mp4 ファイルに変換するなど、トランスコードするために多くのパラメーターを追加する必要があります。 「出力.mp4」。

import os
inputfile = r'd:\temp\input.m3u8'
outputfile = r'd:\temp\output.mp4'
ffmpeg_path = r'"D:\Program Files\ffmpeg\bin\ffmpeg.exe"'
command = f'{ffmpeg_path} -allowed_extensions ALL -protocol_whitelist "file,http,https,crypto,tcp" -i "{inputfile}" -c copy "{outputfile}"'

'''
print(command)
输出:
"D:\Program Files\ffmpeg\bin\ffmpeg.exe" -allowed_extensions ALL -protocol_whitelist "file,http,https,crypto,tcp" -i "d:\temp\input.m3u8" -c copy "d:\temp\output.mp4"
'''

os.system(command)

ここのコマンド文字列は明らかに問題ありませんが、os.system(command) に関しては同じエラーが再び発生します。

 

二重引用符の問題であることに再び気付きました。ffmpeg の背後にあるすべてのパラメーターを削除し、メイン プログラムのみを実行するとどうなりますか? 試してください: os.system(ffmpeg_path)

e23cd73376934d2d942af1007c3752b5.png

その結果、問題なく動作します。ffmpeg パラメータを二重引用符で実行できないためですか?

ただし、ffmpeg では、-protocol_whitelist パラメーターの後ろにあるタイプ「file、http、https、crypto、tcp」には二重引用符が必要であり、単一引用符を変更または削除することは違法です。-i の後の入力ファイル パスと最後の出力ファイル パスにスペースがある場合は、二重引用符も追加する必要があります。

何度もデバッグした後、ffmpeg が完全なパスを追加しなければ、os.system(command) は正常に実行できることがわかりました。ただし、前提条件の設定を行う必要があります。システム パスの変数に ffmpeg のパスを追加する必要があります (具体的な操作については詳しく説明しません)。

この考え方によると、パラメータの二重引用符を追加する必要があるため、メインプログラムのパス名に二重引用符を付けずに行うにはどうすればよいですか? 気まぐれでした: ffmpeg のパスが古いスタイルの 8 ビット文字のショート パスを使用しているとしたらどうなるでしょうか? 長いパスの「Program Files」を「Progra~1」に変更し、コードを次のように変更します。

inputfile = r'd:\temp\input.m3u8'
outputfile = r'd:\temp\output.mp4'
ffmpeg_path = r'D:\Progra~1\ffmpeg\bin\ffmpeg.exe'
command = f'{ffmpeg_path} -allowed_extensions ALL -protocol_whitelist "file,http,https,crypto,tcp" -i "{inputfile}" -c copy "{outputfile}"'

os.system(command)

予期せず、os.system(command) が正常に実行されました。ffmpeg トランスコード情報は画面上をスクロールし続け、滝のように急いでいます。

b5ff50d5d3d643a395793ac4df875ac9.png

ショート パス表現の「Progra~1」は、Windows システムの絶対パスとも言えるもので、スペースや奇妙な文字を含むパスに完全にアクセスできます.これは、何年も前の Win9x 時代の遊び方です。人々は今でもそれを覚えていますか?メソッドは古いですが、機能します。

要約すると: os.system() のバグは次の場所にあります:

条件 1: コマンド ラインのメイン プログラム パスにスペースが含まれる場合、パスには二重引用符が必要です。

条件 2: コマンド ラインのパラメーターに二重引用符が含まれている。

これら 2 つの条件が満たされると、操作は次のエラーを報告します。

私の現在の Python バージョンは 3.10 です。おそらく os.system() 関数は、二重引用符で囲まれた DOS コマンド ライン パラメータのような状況を考慮していません。

解決:

1. メイン プログラムのパスを旧式の 8 文字のショート パスに変更し、二重引用符を削除します。次のパラメータは二重引用符を保持しているため、変更する必要はありません。

また

2. メイン プログラムのパスを Windows システムの環境変数 %PATH% に追加すると、os.system() はパス名を追加せずにプログラム名を直接使用できます。

上記の要約は少し長くなりました. os.system() を使用してffmpegを正常に実行するかどうかの組み合わせと一致を要約するために、より一般的な表を作成しましょう:

シリアルナンバー プログラム名 パラメータ 結果
(1) 長いパスを持つプログラム名 パラメータ パスに二重引用符がない場合、エラーが報告されます
(2) "長いパスを持つプログラム名" パラメータ パスとパラメーターの両方に二重引用符がありますが、エラーが報告されます。バグだと思います。
(3) "長いパスを持つプログラム名" パラメータ パラメーターには二重引用符がありません。プログラムが一部のパラメーターに二重引用符を必要としない場合は、正常に実行できますが、そうでない場合はエラーが報告されます。
(4) "長いパスを持つプログラム名" 実行することはできますが、パラメーターを指定しないと、プログラムを実行しても期待どおりの結果が得られない場合があります。
(5) プログラム名 パラメータ プログラム名の前にパスはありません。成功するには、プログラムが現在のパスまたはシステムの %PATH% 変数にある必要があります。そうでない場合、エラーが報告されます。
(6) 短いパスを持つプログラム名 「パラメータ」 成功。ショート パスのプログラム名は、二重引用符で囲む必要はありません。

最後のトリック: 短いパスを取得するには?

方法 1: dir /x コマンドを使用して、 cmd コマンド プロンプトで表示します

方法 2: Python コードは、win32api の GetShortPathName 関数をインポートして、以下を取得します。

from win32api import GetShortPathName
ffmpeg_path = r'D:\Program Files\ffmpeg\bin\ffmpeg.exe'
ffmpeg_path = GetShortPathName(ffmpeg_path)
'''
print(ffmpeg_path)
输出:
'D:\Progra~1\ffmpeg\bin\ffmpeg.exe'
'''

おすすめ

転載: blog.csdn.net/Scott0902/article/details/129446831