テクノロジー 開発 非公開: Python のサブプロセスとは何ですか? 【5つの使用例】

Python のサブプロセスとは何ですか? 【5つの使用例】

サブプロセスを使用すると、まったく新しいレベルでオペレーティング システムと対話できるようになります。

私たちのコンピュータは常にサブプロセスを実行しています。実際、この記事を読んでいるだけでも、ネットワーク マネージャーやインターネット ブラウザ自体など、多くのプロセスを実行していることになります。

これのすばらしい点は、コンピューター上で行うすべてのアクションにはサブプロセスの呼び出しが含まれることです。これは、Python で単純な 「hello world」 スクリプトを作成している場合でも当てはまります。

サブプロセス の概念は、プログラミングをしばらく学習したことがあっても曖昧に思えるかもしれません。この記事では、サブプロセスの主な概念と、Python サブプロセス標準ライブラリの 使用方法について詳しく説明します。

このチュートリアルを終えると、次のことができるようになります。

  • サブプロセスの概念を理解する
  • Python サブプロセス ライブラリの基本を学習している
  • 役立つ例を使って Python スキルを練習しました

それでは始めましょう

サブプロセスの概念

大まかに言うと、サブプロセスとは、別のプロセスによって作成された コンピューター プロセス です。

サブプロセスは、各親プロセスの背後で子プロセスが実行されているツリーとして考えることができます。非常にわかりにくいかもしれませんが、簡単な図で見てみましょう。

コンピューター上で実行されているプロセスを視覚化する方法はいくつかあります。たとえば、UNIX (Linux および MAC) には、対話型プロセス ビューアである htop があります。

Htopプロセスビューア
Htopプロセスビューア

ツリー モードは、 実行中のサブプロセスを確認するのに最も便利なツールです。 F5 でアクティブ化できます。

コマンドセクションをよく見ると、コンピューター上で実行されているプロセスの構造に気づくことができます。

Htopプロセス構造
すべては、コンピュータ上の各プロセスを開始するコマンドである /sbin/init から始まります。その時点から、 xfce4-screenshoter xfce4-terminal などの他のプロセスの始まりがわかります (これにより、さらに多くのサブプロセスが発生します)。

Windows を見てみると、マシン上でクラッシュするプログラムを強制終了するときに役立つ神話的な タスク マネージャー があります。

ウィンドウズタスクマネージャー
ウィンドウズタスクマネージャー

今、私たちは非常に明確なコンセプトを持っています。 Python でサブプロセスを実装する方法を見てみましょう。

Python のサブプロセス

Python のサブプロセスは、Python スクリプトがオペレーティング システム (OS) に委任するタスクです。

サブプロセス ライブラリを使用すると、Python から直接サブプロセスを実行および管理できます。これには、標準入力 stdin 、標準出力 stdout 、および戻りコードの操作が含まれます。

これは Python 標準ライブラリの一部であるため、PIP を使用してインストールする必要はありません。

したがって、モジュールをインポートするだけで、Python でサブプロセスの使用を開始できます。

 import subprocess

# Using the module ....

注: この記事を進めるには、Python 3.5 以降が必要です。

現在使用している Python のバージョンを確認するには、実行するだけです。

 ❯ python --version
Python 3.9.5 # My result

取得した Python バージョンが 2.x の場合は、次のコマンドを使用できます。

 python3 --version

トピックを続けると、サブプロセス ライブラリの背後にある主なアイデアは、必要なコマンドを Python インタープリターから直接実行することで OS と対話できるようにすることです。

つまり、OS が許可する限り (ルート ファイルシステムを削除しない限り 😅)、やりたいことは何でもできるということです。

現在のディレクトリのファイルを一覧表示する簡単なスクリプトを作成して、その使用方法を見てみましょう。

最初のサブプロセス アプリケーション

まず、ファイル list_dir.py を作成しましょう。これは、ファイルのリストを実験するファイルになります。

 touch list_dir.py

次に、そのファイルを開いて次のコードを使用してみましょう。

 import subprocess 

subprocess.run('ls')

まず、subprocess モジュールをインポートし、次に実行する関数 run を 使用し、引数として渡すコマンドを使用します。

この関数は、 subprocess.Popen へのわかりやすいショートカットとして Python 3.5 で導入されました。 subprocess.run 関数を使用すると、後で通信を呼び出すオプションがある Popen とは対照的に、コマンドを実行してその完了を待つことができます。

コード出力について言えば、 ls は、現在のディレクトリのファイルを一覧表示する UNIX コマンドです。したがって、このコマンドを実行すると、現在のディレクトリに存在するファイルの一覧が表示されます。

 ❯ python list_dir.py
example.py  LICENSE  list_dir.py  README.md

注: Windows を使用している場合は、別のコマンドを使用する必要があることに注意してください。たとえば、 「ls」を 使用する代わりに 「dir」 を使用できます。

これは単純すぎるように思えるかもしれませんが、それは正しいです。シェルがもたらすすべてのパワーを最大限に活用したいと考えています。それでは、サブプロセスを使用してシェルに引数を渡す方法を学びましょう。

たとえば、隠しファイル (ドットで始まるファイル) もリストし、ファイルのすべてのメタデータもリストするには、次のコードを作成します。

 import subprocess

# subprocess.run('ls')  # Simple command

subprocess.run('ls -la', shell=True)

このコマンドを文字列として実行し、引数 shell を使用します。つまり、サブプロセスの実行開始時にシェルを呼び出しており、コマンド引数はシェルによって直接解釈されます。

ただし、 shell=True の使用には多くの欠点があり、最悪の場合はセキュリティ漏洩の可能性があります。これらについては 公式ドキュメント で読むことができます。

コマンドを run 関数に渡す最良の方法は、 lst[0] が呼び出すコマンド (この場合は ls) で、 lst[n] がそのコマンドの引数であるリストを使用することです。

そうすると、コードは次のようになります。

 import subprocess

# subprocess.run('ls')  # Simple command

# subprocess.run('ls -la', shell=True) # Dangerous command

subprocess.run(['ls', '-la'])

サブプロセスの標準出力を変数に保存したい場合は、引数 Capture_output を true に設定することで実行できます。

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True)

print(list_of_files.stdout)

❯ python list_dir.py 
b'total 36\ndrwxr-xr-x 3 daniel daniel 4096 may 20 21:08 .\ndrwx------ 30 daniel daniel 4096 may 20 18:03 ..\n-rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py\ndrwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git\n-rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore\n-rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py\n-rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE\n-rw-r--r-- 1 daniel daniel 216 may 20 22:12 list_dir.py\n-rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.md\n'

プロセスの出力にアクセスするには、インスタンス属性 stdout を使用します。

この場合、出力をバイトではなく文字列として保存する必要があり、text 引数を true に設定することでそれを行うことができます。

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True, text=True)

print(list_of_files.stdout)

❯ python list_dir.py
total 36
drwxr-xr-x  3 daniel daniel 4096 may 20 21:08 .
drwx------ 30 daniel daniel 4096 may 20 18:03 ..
-rw-r--r--  1 daniel daniel   55 may 20 20:18 example.py
drwxr-xr-x  8 daniel daniel 4096 may 20 17:31 .git
-rw-r--r--  1 daniel daniel 2160 may 17 22:23 .gitignore
-rw-r--r--  1 daniel daniel  271 may 20 19:53 internet_checker.py
-rw-r--r--  1 daniel daniel 1076 may 17 22:23 LICENSE
-rw-r--r--  1 daniel daniel  227 may 20 22:14 list_dir.py
-rw-r--r--  1 daniel daniel   22 may 17 22:23 README.md

完璧です。 サブプロセス ライブラリの基本は理解できたので、いくつかの使用例に進みます。

Pythonでのサブプロセスの使用例

このセクションでは、サブプロセス ライブラリの実際の使用法をいくつか検討します。これらはすべて、この Github リポジトリ で確認できます。

プログラムチェッカー

このライブラリの主な用途の 1 つは、単純な OS 操作を実行できることです。

たとえば、プログラムがインストールされているかどうかを確認する単純なスクリプトです。 Linux では、 this コマンドを使用してこれを行うことができます。

 '''Program checker with subprocess'''

import subprocess

program = 'git'

process = subprocess. run(['which', program], capture_output=True, text=True)

if process.returncode == 0: 
    print(f'The program "{program}" is installed')

    print(f'The location of the binary is: {process.stdout}')
else:
    print(f'Sorry the {program} is not installed')

    print(process.stderr)

注: UNIX では、コマンドが成功するとステータス コードは 0 になります。それ以外の場合は、実行中に問題が発生しました。

shell=True 引数を使用していないため、ユーザー入力を安全に取得できます。また、入力が正規表現パターンを使用した有効なプログラムであるかどうかを確認できます。

 import subprocess

import re

programs = input('Separe the programs with a space: ').split()

secure_pattern = '[\w\d]'

for program in programs:

    if not re.match(secure_pattern, program):
        print("Sorry we can't check that program")

        continue

    process = subprocess. run(
        ['which', program], capture_output=True, text=True)

    if process.returncode == 0:
        print(f'The program "{program}" is installed')

        print(f'The location of the binary is: {process.stdout}')
    else:
        print(f'Sorry the {program} is not installed')

        print(process.stderr)

    print('\n')

この場合、ユーザーからプログラムを取得し、プログラム文字列に文字と数字のみが含まれていることを証明する正規表現を使用しています。 for a ループで各プログラムの存在を確認します。

注: このオンライン正規表現テスターを確認してください。

Python での単純な Grep

友人の トムは、 テキスト ファイルと別の大きなファイルにパターンのリストを持っており、そこから各パターンの一致数を取得したいと考えています。彼は、すべてのパターンに対して grep コマンドを実行するのに何時間も費やしていました。

幸いなことに、あなたは Python を使用してこの問題を解決する方法を知っているので、彼がこのタスクを数秒で完了できるよう手伝うことになります。

 import subprocess

patterns_file = 'patterns.txt'
readfile = 'romeo-full.txt'

with open(patterns_file, 'r') as f:
    for pattern in f:
        pattern = pattern.strip()

        process = subprocess.run(
            ['grep', '-c', f'{pattern}', readfile], capture_output=True, text=True)

        if int(process.stdout) == 0:
            print(
                f'The pattern "{pattern}" did not match any line of {readfile}')

            continue

        print(f'The pattern "{pattern}" matched {process.stdout.strip()} times')

このファイルを見て、操作したいファイル名である 2 つの変数を定義します。次に、すべてのパターンを含むファイルを開き、それらを繰り返し処理します。次に、 「-c」 フラグ (カウントを意味します) を指定して grep コマンドを実行するサブプロセスを呼び出し、条件付きの一致の出力を決定します。

このファイルを実行すると (テキスト ファイルは Github リポジトリ からダウンロードできることに注意してください)

サブプロセスを使用して virtualenv をセットアップする

Python で実行できる最も優れた機能の 1 つは、プロセスの自動化です。この種のスクリプトを使用すると、週に数時間の時間を節約できます。

たとえば、仮想環境を作成し、すべての依存関係をインストールするために現在のディレクトリで requirements.txt ファイルを検索するセットアップ スクリプトを作成します。

 import subprocess

from pathlib import Path


VENV_NAME = '.venv'
REQUIREMENTS = 'requirements.txt'

process1 = subprocess.run(['which', 'python3'], capture_output=True, text=True)

if process1.returncode != 0:
    raise OSError('Sorry python3 is not installed')

python_bin = process1.stdout.strip()

print(f'Python found in: {python_bin}')

process2 = subprocess.run('echo "$SHELL"', shell=True, capture_output=True, text=True)

shell_bin = process2.stdout.split('/')[-1]

create_venv = subprocess.run([python_bin, '-m', 'venv', VENV_NAME], check=True)

if create_venv.returncode == 0:
    print(f'Your venv {VENV_NAME} has been created')

pip_bin = f'{VENV_NAME}/bin/pip3'

if Path(REQUIREMENTS).exists():
    print(f'Requirements file "{REQUIREMENTS}" found')
    print('Installing requirements')
    subprocess.run([pip_bin, 'install', '-r', REQUIREMENTS])

    print('Process completed! Now activate your environment with "source .venv/bin/activate"')

else:
    print("No requirements specified ...")

この場合、複数のプロセスを使用し、Python スクリプトで必要なデータを解析しています。また、 requirements.txt ファイルが存在するかどうかを判断できる pathlib ライブラリも使用しています。

Python ファイルを実行すると、OS で何が起こっているかについての有益なメッセージが表示されます。

 ❯ python setup.py 
Python found in: /usr/bin/python3
Your venv .venv has been created
Requirements file "requirements.txt" found
Installing requirements
Collecting asgiref==3.3.4 .......
Process completed! Now activate your environment with "source .venv/bin/activate"

標準出力を変数にリダイレクトしていないため、インストール プロセスから出力を取得していることに注意してください。

別のプログラミング言語を実行する

Python で他のプログラミング言語を実行し、それらのファイルから出力を取得できます。これが可能なのは、サブプロセスがオペレーティング システムと直接対話するためです。

たとえば、C++ と Java で hello world プログラムを作成してみましょう。次のファイルを実行するには、 C++ および Java コンパイラをインストールする必要があります。

helloworld.cpp

 #include <iostream>

int main(){
    std::cout << "This is a hello world in C++" << std::endl;
    return 0;
}


helloworld.java

 class HelloWorld{  
    public static void main(String args[]){  
     System.out.println("This is a hello world in Java");  
    }  
}  


単純な Python のワンライナーに比べてコードが多く見えることは承知していますが、これはテスト目的だけです。

ディレクトリ内のすべての C++ ファイルと Java ファイルを実行する Python スクリプトを作成します。これを行うには、まずファイル拡張子に応じてファイルのリストを取得する必要があります。glob 使用するとそれが簡単に行えます。

 from glob import glob

# Gets files with each extension
java_files = glob('*.java')

cpp_files = glob('*.cpp')

その後、サブプロセスの使用を開始して、各種類のファイルを実行できます。

 for file in cpp_files:
    process = subprocess.run(f'g++ {file} -o out; ./out', shell=True, capture_output=True, text=True)
    
    output = process.stdout.strip() + ' BTW this was runned by Python'

    print(output)

for file in java_files:
    without_ext = file.strip('.java')
    process = subprocess.run(f'java {file}; java {without_ext}',shell=True, capture_output=True, text=True)

    output = process.stdout.strip() + ' A Python subprocess runned this :)'
    print(output)

ちょっとしたトリックの 1 つは、文字列関数 ストリップ を使用して出力を変更し、必要なものだけを取得することです。

注: 出力をメモリにロードしているため、メモリ リークが発生する可能性があるため、大きな Java または C++ ファイルを実行する場合は注意してください。

外部プログラムを開く

サブプロセスを通じてバイナリの場所を呼び出すだけで、他のプログラムを実行できます。

私の好みの Web ブラウザである Brave を開いて試してみましょう。

 import subprocess

subprocess.run('brave')

これにより、ブラウザ インスタンスが開きます。すでにブラウザを実行している場合は別のタブが開きます。

開いているブラウザ
開いているブラウザ

フラグを受け入れる他のプログラムと同様に、フラグを使用して目的の動作を生成できます。

 import subprocess

subprocess.run(['brave', '--incognito']) 
シークレット フラグ
シークレット フラグ

総括する

サブプロセスは、別のプロセスによって作成されるコンピュータ プロセスです。 htop やタスク マネージャーなどのツールを使用して、コンピューターが実行しているプロセスを確認できます。

Python には、サブプロセスを操作するための独自のライブラリがあります。現在、 run 関数はサブプロセスを作成および管理するためのシンプルなインターフェイスを提供します。

OS と直接対話するため、あらゆる種類のアプリケーションを作成できます。

最後に、学習するための最良の方法は、自分が使いたいものを作成することであることを忘れないでください。

「 Python のサブプロセスとは何ですか? 【5つの使用例】」についてわかりやすく解説!絶対に観るべきベスト2動画

【完全版】この動画1本でPythonの基礎を習得!忙しい人のための速習コース(Python入門)
【完全解説】Pythonでできること10選+具体例50個

サブプロセスを使用すると、まったく新しいレベルでオペレーティング システムと対話できるようになります。

私たちのコンピュータは常にサブプロセスを実行しています。実際、この記事を読んでいるだけでも、ネットワーク マネージャーやインターネット ブラウザ自体など、多くのプロセスを実行していることになります。

これのすばらしい点は、コンピューター上で行うすべてのアクションにはサブプロセスの呼び出しが含まれることです。これは、Python で単純な 「hello world」 スクリプトを作成している場合でも当てはまります。

サブプロセス の概念は、プログラミングをしばらく学習したことがあっても曖昧に思えるかもしれません。この記事では、サブプロセスの主な概念と、Python サブプロセス標準ライブラリの 使用方法について詳しく説明します。

このチュートリアルを終えると、次のことができるようになります。

  • サブプロセスの概念を理解する
  • Python サブプロセス ライブラリの基本を学習している
  • 役立つ例を使って Python スキルを練習しました

それでは始めましょう

サブプロセスの概念

大まかに言うと、サブプロセスとは、別のプロセスによって作成された コンピューター プロセス です。

サブプロセスは、各親プロセスの背後で子プロセスが実行されているツリーとして考えることができます。非常にわかりにくいかもしれませんが、簡単な図で見てみましょう。

コンピューター上で実行されているプロセスを視覚化する方法はいくつかあります。たとえば、UNIX (Linux および MAC) には、対話型プロセス ビューアである htop があります。

Htopプロセスビューア
Htopプロセスビューア

ツリー モードは、 実行中のサブプロセスを確認するのに最も便利なツールです。 F5 でアクティブ化できます。

コマンドセクションをよく見ると、コンピューター上で実行されているプロセスの構造に気づくことができます。

Htopプロセス構造
すべては、コンピュータ上の各プロセスを開始するコマンドである /sbin/init から始まります。その時点から、 xfce4-screenshoter xfce4-terminal などの他のプロセスの始まりがわかります (これにより、さらに多くのサブプロセスが発生します)。

Windows を見てみると、マシン上でクラッシュするプログラムを強制終了するときに役立つ神話的な タスク マネージャー があります。

ウィンドウズタスクマネージャー
ウィンドウズタスクマネージャー

今、私たちは非常に明確なコンセプトを持っています。 Python でサブプロセスを実装する方法を見てみましょう。

Python のサブプロセス

Python のサブプロセスは、Python スクリプトがオペレーティング システム (OS) に委任するタスクです。

サブプロセス ライブラリを使用すると、Python から直接サブプロセスを実行および管理できます。これには、標準入力 stdin 、標準出力 stdout 、および戻りコードの操作が含まれます。

これは Python 標準ライブラリの一部であるため、PIP を使用してインストールする必要はありません。

したがって、モジュールをインポートするだけで、Python でサブプロセスの使用を開始できます。

 import subprocess

# Using the module ....

注: この記事を進めるには、Python 3.5 以降が必要です。

現在使用している Python のバージョンを確認するには、実行するだけです。

 ❯ python --version
Python 3.9.5 # My result

取得した Python バージョンが 2.x の場合は、次のコマンドを使用できます。

 python3 --version

トピックを続けると、サブプロセス ライブラリの背後にある主なアイデアは、必要なコマンドを Python インタープリターから直接実行することで OS と対話できるようにすることです。

つまり、OS が許可する限り (ルート ファイルシステムを削除しない限り 😅)、やりたいことは何でもできるということです。

現在のディレクトリのファイルを一覧表示する簡単なスクリプトを作成して、その使用方法を見てみましょう。

最初のサブプロセス アプリケーション

まず、ファイル list_dir.py を作成しましょう。これは、ファイルのリストを実験するファイルになります。

 touch list_dir.py

次に、そのファイルを開いて次のコードを使用してみましょう。

 import subprocess 

subprocess.run('ls')

まず、subprocess モジュールをインポートし、次に実行する関数 run を 使用し、引数として渡すコマンドを使用します。

この関数は、 subprocess.Popen へのわかりやすいショートカットとして Python 3.5 で導入されました。 subprocess.run 関数を使用すると、後で通信を呼び出すオプションがある Popen とは対照的に、コマンドを実行してその完了を待つことができます。

コード出力について言えば、 ls は、現在のディレクトリのファイルを一覧表示する UNIX コマンドです。したがって、このコマンドを実行すると、現在のディレクトリに存在するファイルの一覧が表示されます。

 ❯ python list_dir.py
example.py  LICENSE  list_dir.py  README.md

注: Windows を使用している場合は、別のコマンドを使用する必要があることに注意してください。たとえば、 「ls」を 使用する代わりに 「dir」 を使用できます。

これは単純すぎるように思えるかもしれませんが、それは正しいです。シェルがもたらすすべてのパワーを最大限に活用したいと考えています。それでは、サブプロセスを使用してシェルに引数を渡す方法を学びましょう。

たとえば、隠しファイル (ドットで始まるファイル) もリストし、ファイルのすべてのメタデータもリストするには、次のコードを作成します。

 import subprocess

# subprocess.run('ls')  # Simple command

subprocess.run('ls -la', shell=True)

このコマンドを文字列として実行し、引数 shell を使用します。つまり、サブプロセスの実行開始時にシェルを呼び出しており、コマンド引数はシェルによって直接解釈されます。

ただし、 shell=True の使用には多くの欠点があり、最悪の場合はセキュリティ漏洩の可能性があります。これらについては 公式ドキュメント で読むことができます。

コマンドを run 関数に渡す最良の方法は、 lst[0] が呼び出すコマンド (この場合は ls) で、 lst[n] がそのコマンドの引数であるリストを使用することです。

そうすると、コードは次のようになります。

 import subprocess

# subprocess.run('ls')  # Simple command

# subprocess.run('ls -la', shell=True) # Dangerous command

subprocess.run(['ls', '-la'])

サブプロセスの標準出力を変数に保存したい場合は、引数 Capture_output を true に設定することで実行できます。

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True)

print(list_of_files.stdout)

❯ python list_dir.py 
b'total 36\ndrwxr-xr-x 3 daniel daniel 4096 may 20 21:08 .\ndrwx------ 30 daniel daniel 4096 may 20 18:03 ..\n-rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py\ndrwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git\n-rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore\n-rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py\n-rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE\n-rw-r--r-- 1 daniel daniel 216 may 20 22:12 list_dir.py\n-rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.md\n'

プロセスの出力にアクセスするには、インスタンス属性 stdout を使用します。

この場合、出力をバイトではなく文字列として保存する必要があり、text 引数を true に設定することでそれを行うことができます。

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True, text=True)

print(list_of_files.stdout)

❯ python list_dir.py
total 36
drwxr-xr-x  3 daniel daniel 4096 may 20 21:08 .
drwx------ 30 daniel daniel 4096 may 20 18:03 ..
-rw-r--r--  1 daniel daniel   55 may 20 20:18 example.py
drwxr-xr-x  8 daniel daniel 4096 may 20 17:31 .git
-rw-r--r--  1 daniel daniel 2160 may 17 22:23 .gitignore
-rw-r--r--  1 daniel daniel  271 may 20 19:53 internet_checker.py
-rw-r--r--  1 daniel daniel 1076 may 17 22:23 LICENSE
-rw-r--r--  1 daniel daniel  227 may 20 22:14 list_dir.py
-rw-r--r--  1 daniel daniel   22 may 17 22:23 README.md

完璧です。 サブプロセス ライブラリの基本は理解できたので、いくつかの使用例に進みます。

Pythonでのサブプロセスの使用例

このセクションでは、サブプロセス ライブラリの実際の使用法をいくつか検討します。これらはすべて、この Github リポジトリ で確認できます。

プログラムチェッカー

このライブラリの主な用途の 1 つは、単純な OS 操作を実行できることです。

たとえば、プログラムがインストールされているかどうかを確認する単純なスクリプトです。 Linux では、 this コマンドを使用してこれを行うことができます。

 '''Program checker with subprocess'''

import subprocess

program = 'git'

process = subprocess. run(['which', program], capture_output=True, text=True)

if process.returncode == 0: 
    print(f'The program "{program}" is installed')

    print(f'The location of the binary is: {process.stdout}')
else:
    print(f'Sorry the {program} is not installed')

    print(process.stderr)

注: UNIX では、コマンドが成功するとステータス コードは 0 になります。それ以外の場合は、実行中に問題が発生しました。

shell=True 引数を使用していないため、ユーザー入力を安全に取得できます。また、入力が正規表現パターンを使用した有効なプログラムであるかどうかを確認できます。

 import subprocess

import re

programs = input('Separe the programs with a space: ').split()

secure_pattern = '[\w\d]'

for program in programs:

    if not re.match(secure_pattern, program):
        print("Sorry we can't check that program")

        continue

    process = subprocess. run(
        ['which', program], capture_output=True, text=True)

    if process.returncode == 0:
        print(f'The program "{program}" is installed')

        print(f'The location of the binary is: {process.stdout}')
    else:
        print(f'Sorry the {program} is not installed')

        print(process.stderr)

    print('\n')

この場合、ユーザーからプログラムを取得し、プログラム文字列に文字と数字のみが含まれていることを証明する正規表現を使用しています。 for a ループで各プログラムの存在を確認します。

注: このオンライン正規表現テスターを確認してください。

Python での単純な Grep

友人の トムは、 テキスト ファイルと別の大きなファイルにパターンのリストを持っており、そこから各パターンの一致数を取得したいと考えています。彼は、すべてのパターンに対して grep コマンドを実行するのに何時間も費やしていました。

幸いなことに、あなたは Python を使用してこの問題を解決する方法を知っているので、彼がこのタスクを数秒で完了できるよう手伝うことになります。

 import subprocess

patterns_file = 'patterns.txt'
readfile = 'romeo-full.txt'

with open(patterns_file, 'r') as f:
    for pattern in f:
        pattern = pattern.strip()

        process = subprocess.run(
            ['grep', '-c', f'{pattern}', readfile], capture_output=True, text=True)

        if int(process.stdout) == 0:
            print(
                f'The pattern "{pattern}" did not match any line of {readfile}')

            continue

        print(f'The pattern "{pattern}" matched {process.stdout.strip()} times')

このファイルを見て、操作したいファイル名である 2 つの変数を定義します。次に、すべてのパターンを含むファイルを開き、それらを繰り返し処理します。次に、 「-c」 フラグ (カウントを意味します) を指定して grep コマンドを実行するサブプロセスを呼び出し、条件付きの一致の出力を決定します。

このファイルを実行すると (テキスト ファイルは Github リポジトリ からダウンロードできることに注意してください)

サブプロセスを使用して virtualenv をセットアップする

Python で実行できる最も優れた機能の 1 つは、プロセスの自動化です。この種のスクリプトを使用すると、週に数時間の時間を節約できます。

たとえば、仮想環境を作成し、すべての依存関係をインストールするために現在のディレクトリで requirements.txt ファイルを検索するセットアップ スクリプトを作成します。

 import subprocess

from pathlib import Path


VENV_NAME = '.venv'
REQUIREMENTS = 'requirements.txt'

process1 = subprocess.run(['which', 'python3'], capture_output=True, text=True)

if process1.returncode != 0:
    raise OSError('Sorry python3 is not installed')

python_bin = process1.stdout.strip()

print(f'Python found in: {python_bin}')

process2 = subprocess.run('echo "$SHELL"', shell=True, capture_output=True, text=True)

shell_bin = process2.stdout.split('/')[-1]

create_venv = subprocess.run([python_bin, '-m', 'venv', VENV_NAME], check=True)

if create_venv.returncode == 0:
    print(f'Your venv {VENV_NAME} has been created')

pip_bin = f'{VENV_NAME}/bin/pip3'

if Path(REQUIREMENTS).exists():
    print(f'Requirements file "{REQUIREMENTS}" found')
    print('Installing requirements')
    subprocess.run([pip_bin, 'install', '-r', REQUIREMENTS])

    print('Process completed! Now activate your environment with "source .venv/bin/activate"')

else:
    print("No requirements specified ...")

この場合、複数のプロセスを使用し、Python スクリプトで必要なデータを解析しています。また、 requirements.txt ファイルが存在するかどうかを判断できる pathlib ライブラリも使用しています。

Python ファイルを実行すると、OS で何が起こっているかについての有益なメッセージが表示されます。

 ❯ python setup.py 
Python found in: /usr/bin/python3
Your venv .venv has been created
Requirements file "requirements.txt" found
Installing requirements
Collecting asgiref==3.3.4 .......
Process completed! Now activate your environment with "source .venv/bin/activate"

標準出力を変数にリダイレクトしていないため、インストール プロセスから出力を取得していることに注意してください。

別のプログラミング言語を実行する

Python で他のプログラミング言語を実行し、それらのファイルから出力を取得できます。これが可能なのは、サブプロセスがオペレーティング システムと直接対話するためです。

たとえば、C++ と Java で hello world プログラムを作成してみましょう。次のファイルを実行するには、 C++ および Java コンパイラをインストールする必要があります。

helloworld.cpp

 #include <iostream>

int main(){
    std::cout << "This is a hello world in C++" << std::endl;
    return 0;
}


helloworld.java

 class HelloWorld{  
    public static void main(String args[]){  
     System.out.println("This is a hello world in Java");  
    }  
}  


単純な Python のワンライナーに比べてコードが多く見えることは承知していますが、これはテスト目的だけです。

ディレクトリ内のすべての C++ ファイルと Java ファイルを実行する Python スクリプトを作成します。これを行うには、まずファイル拡張子に応じてファイルのリストを取得する必要があります。glob 使用するとそれが簡単に行えます。

 from glob import glob

# Gets files with each extension
java_files = glob('*.java')

cpp_files = glob('*.cpp')

その後、サブプロセスの使用を開始して、各種類のファイルを実行できます。

 for file in cpp_files:
    process = subprocess.run(f'g++ {file} -o out; ./out', shell=True, capture_output=True, text=True)
    
    output = process.stdout.strip() + ' BTW this was runned by Python'

    print(output)

for file in java_files:
    without_ext = file.strip('.java')
    process = subprocess.run(f'java {file}; java {without_ext}',shell=True, capture_output=True, text=True)

    output = process.stdout.strip() + ' A Python subprocess runned this :)'
    print(output)

ちょっとしたトリックの 1 つは、文字列関数 ストリップ を使用して出力を変更し、必要なものだけを取得することです。

注: 出力をメモリにロードしているため、メモリ リークが発生する可能性があるため、大きな Java または C++ ファイルを実行する場合は注意してください。

外部プログラムを開く

サブプロセスを通じてバイナリの場所を呼び出すだけで、他のプログラムを実行できます。

私の好みの Web ブラウザである Brave を開いて試してみましょう。

 import subprocess

subprocess.run('brave')

これにより、ブラウザ インスタンスが開きます。すでにブラウザを実行している場合は別のタブが開きます。

開いているブラウザ
開いているブラウザ

フラグを受け入れる他のプログラムと同様に、フラグを使用して目的の動作を生成できます。

 import subprocess

subprocess.run(['brave', '--incognito']) 
シークレット フラグ
シークレット フラグ

総括する

サブプロセスは、別のプロセスによって作成されるコンピュータ プロセスです。 htop やタスク マネージャーなどのツールを使用して、コンピューターが実行しているプロセスを確認できます。

Python には、サブプロセスを操作するための独自のライブラリがあります。現在、 run 関数はサブプロセスを作成および管理するためのシンプルなインターフェイスを提供します。

OS と直接対話するため、あらゆる種類のアプリケーションを作成できます。

最後に、学習するための最良の方法は、自分が使いたいものを作成することであることを忘れないでください。

「 Python のサブプロセスとは何ですか? 【5つの使用例】」についてわかりやすく解説!絶対に観るべきベスト2動画

【完全版】この動画1本でPythonの基礎を習得!忙しい人のための速習コース(Python入門)
【完全解説】Pythonでできること10選+具体例50個