PYTHON MEBY

Pythonで外部コマンドを実行(os.system, subprocess)

この記事では、Pythonから外部コマンドを実行する方法について説明します。`os.system`と`subprocess`モジュールを使った方法、それぞれのメリット・デメリット、セキュリティに関する考慮事項を解説します。

目次

os.system() 関数による外部コマンドの実行

最も単純な方法は`os.system()`関数です。コマンドを文字列として渡し、実行します。

import os
ret = os.system('ls -l')
print(f'Return code: {ret}')

ただし、標準出力や標準エラーを直接扱うことができず、戻り値もプラットフォーム依存です。そのため、複雑な処理には向きません。

subprocess モジュールによる外部コマンドの実行

`subprocess`モジュールは、外部コマンドを実行するためのより高度な機能を提供します。`run()`、`Popen()`など、複数の関数とクラスがあります。

subprocess.run() 関数

`subprocess.run()`は、コマンドを実行し、その結果を`CompletedProcess`オブジェクトとして返します。

import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(f'Return code: {result.returncode}')
print(f'Stdout: {result.stdout}')
print(f'Stderr: {result.stderr}')

`capture_output=True`で標準出力と標準エラーをキャプチャし、`text=True`で文字列として取得します。

subprocess.Popen() クラス

`subprocess.Popen()`は、より柔軟なコマンド実行を可能にします。非同期処理やパイプライン処理などが行えます。

import subprocess
process = subprocess.Popen(['grep', 'python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate(input=b'This is a test line.')
print(f'Stdout: {stdout.decode()}')
print(f'Stderr: {stderr.decode()}')

stdin、stdout、stderrで標準入出力のパイプラインを制御できます。`communicate()`で入出力を行います。

セキュリティに関する考慮事項

外部コマンドを実行する際には、コマンドインジェクション攻撃に注意する必要があります。ユーザーからの入力に基づいてコマンドを構築する場合は、`shlex.quote()`関数を使用して、特別な文字を適切にエスケープ処理することが重要です。

import shlex, subprocess
user_input = 'some file.txt'
command = ['ls', shlex.quote(user_input)]
subprocess.run(command)

標準出力と標準エラーの処理

`subprocess.run()`や`subprocess.Popen()`では、`capture_output=True`オプションを使用して、コマンドの標準出力と標準エラーをPythonプログラム内で取得できます。

import subprocess
result = subprocess.run(['ls', '-l', 'nonexistent_file'], capture_output=True, text=True, check=True)
print(result.stdout)
print(result.stderr)

戻り値の確認

コマンドの実行結果を確認するには、`subprocess.run()`の`returncode`属性をチェックします。0は成功、それ以外の値はエラーを示します。

import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True, check=True)
if result.returncode == 0:
    print('コマンドが正常に実行されました')
else:
    print('コマンドの実行に失敗しました')

関連記事