Python & AI Tutorials Logo
Python プログラミング

29. オペレーティングシステムとの連携: sys と os

Python プログラムは単独で存在しているわけではありません。ファイル、ディレクトリ、環境設定、そしてプログラムの起動や通信の方法を管理するオペレーティングシステム上で動作します。sysos モジュールは、この環境とやり取りするためのツールを提供し、コマンドライン引数の受け取り、環境変数の読み取り、ファイルシステムの移動、ディレクトリの作成や削除をプログラムから行えるようにします。

これらのモジュールを理解すると、Python スクリプトは孤立したコードから、より広いシステムと統合でき、起動時のユーザー入力に応答し、ファイルやフォルダーをプログラムで管理できるプログラムへと変わります。

29.1) コマンドライン引数と sys.argv の利用

ターミナルやコマンドプロンプトから Python スクリプトを実行するとき、追加情報を渡せます。これらは コマンドライン引数(command-line arguments) と呼ばれます。たとえば次のようになります。

bash
python greet.py Alice 25

ここでは、greet.py がスクリプト名で、Alice25 がプログラムに渡される引数です。sys モジュールは sys.argv を通じてこれらの引数にアクセスできます。これは、スクリプト名とすべての引数を文字列として含むリスト(list)です。

29.1.1) sys.argv とは?

sys.argv は次のようなリスト(list)です。

  • sys.argv[0] は常に実行されているスクリプト名です
  • sys.argv[1]sys.argv[2] などは、スクリプト名の後に渡された引数です
  • 見た目が数字でも、すべての要素は文字列です

これがどのように動くかを見るために、簡単なスクリプトを作ってみましょう。

python
# show_args.py
import sys
 
print("Script name:", sys.argv[0])
print("Number of arguments:", len(sys.argv))
print("All arguments:", sys.argv)

このスクリプトを次のように実行すると:

bash
python show_args.py hello world 123

Output:

Script name: show_args.py
Number of arguments: 4
All arguments: ['show_args.py', 'hello', 'world', '123']

sys.argv に 4 つの要素が含まれていることが分かります。スクリプト名に加えて 3 つの引数です。数値の 123 は整数ではなく、文字列の '123' として格納されています。

29.1.2) プログラムでコマンドライン引数を使う

コマンドライン引数を使うと、コードを変更せずにユーザーがプログラムの挙動をカスタマイズできます。次は、最初の引数を名前として使う挨拶プログラムです。

python
# greet.py
import sys
 
if len(sys.argv) < 2:
    print("Usage: python greet.py <name>")
    sys.exit(1)  # エラーコードで終了
 
name = sys.argv[1]
print(f"Hello, {name}!")

これを実行すると:

bash
python greet.py Alice

Output:

Hello, Alice!

名前を指定し忘れた場合は次のようになります。

bash
python greet.py

Output:

Usage: python greet.py <name>

このプログラムは、十分な引数が提供されたかどうかをチェックします。足りない場合は使い方のメッセージを表示し、sys.exit(1) で終了します。1終了コード(exit code) です。慣習として、0 は成功を意味し、0 以外の値はエラーを示します。これにより、別のプログラムやスクリプトが、あなたのプログラムが正しく実行されたかどうかを検出できます。

29.1.3) 引数を他の型に変換する

引数はすべて文字列として渡されるため、変換が必要になることがよくあります。次は長方形の面積を計算するプログラムです。

python
# area.py
import sys
 
if len(sys.argv) < 3:
    print("Usage: python area.py <width> <height>")
    sys.exit(1)
 
try:
    width = float(sys.argv[1])
    height = float(sys.argv[2])
except ValueError:
    print("Error: Width and height must be numbers")
    sys.exit(1)
 
area = width * height
print(f"Area: {area}")

これを実行すると:

bash
python area.py 5.5 3.2

Output:

Area: 17.6

ユーザーが不正な入力をした場合:

bash
python area.py five three

Output:

Error: Width and height must be numbers

try-except ブロック(第 25 章)は変換エラーを適切に処理し、トレースバックでクラッシュする代わりに役に立つフィードバックを提供します。

ユーザーが実行: python script.py arg1 arg2

Python が sys.argv リストを作成

sys.argv[0] = 'script.py'

sys.argv[1] = 'arg1'

sys.argv[2] = 'arg2'

スクリプトが sys.argv にアクセス

引数を文字列として処理

必要なら型を変換

プログラムのロジックで値を使用

29.2) sys でインタプリタと実行時情報を取得する

sys モジュールは、Python インタプリタ自体と実行時環境に関する情報を提供します。これは、デバッグ(debugging)、ログ記録、または異なる Python バージョンやプラットフォームに適応するコードを書くときに便利です。

29.2.1) Python バージョン情報

sys.versionsys.version_info は、どの Python バージョンでコードが実行されているかを教えてくれます。

python
import sys
 
print("Python version string:", sys.version)
print("Version info:", sys.version_info)
print(f"Major version: {sys.version_info.major}")
print(f"Minor version: {sys.version_info.minor}")

Output (example):

Python version string: 3.11.4 (main, Jul  5 2023, 13:45:01) [GCC 11.2.0]
Version info: sys.version_info(major=3, minor=11, micro=4, releaselevel='final', serial=0)
Major version: 3
Minor version: 11

sys.version は人間が読める文字列である一方、sys.version_info はプログラムから比較できる名前付きタプル(named tuple)です。

python
import sys
 
if sys.version_info < (3, 8):
    print("This program requires Python 3.8 or higher")
    sys.exit(1)
 
print("Python version is compatible")

これにより、プログラムは対応している Python バージョンでのみ実行されるようになります。

29.2.2) プラットフォーム情報

sys.platform はオペレーティングシステムを識別します。

python
import sys
 
print("Platform:", sys.platform)
 
if sys.platform == "win32":
    print("Running on Windows")
elif sys.platform == "darwin":
    print("Running on macOS")
elif sys.platform.startswith("linux"):
    print("Running on Linux")
else:
    print("Running on another platform")

Output (on Linux):

Platform: linux
Running on Linux

これにより、たとえば異なるファイルパスやシステムコマンドを使うなど、必要に応じてプラットフォーム固有のコードを書けます。

29.2.3) モジュール検索パス

sys.path は、モジュールを import するときに Python が検索するディレクトリのリスト(list)です。

python
import sys
 
print("Module search paths:")
for path in sys.path:
    print(f"  {path}")

Output (example):

Module search paths:
  /home/user/projects
  /usr/lib/python3.11
  /usr/lib/python3.11/lib-dynload
  /home/user/.local/lib/python3.11/site-packages

最初の要素は通常、スクリプトが置かれているディレクトリです。import を使うと、Python はこれらのパスを順に検索します。sys.path を理解すると、import エラーのデバッグや、カスタムのモジュールディレクトリを追加するときに役立ちます。

29.2.4) 終了コードでプログラムを終了する

sys.exit() を使ってプログラムを停止する方法を見てきました。成功か失敗かを示すために、終了コードを渡せます。

python
import sys
 
def process_data(filename):
    try:
        with open(filename) as f:
            data = f.read()
        # データを処理...
        return True
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found", file=sys.stderr)
        return False
 
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <filename>", file=sys.stderr)
        sys.exit(1)
    
    success = process_data(sys.argv[1])
    sys.exit(0 if success else 1)

終了コードは Unix の慣習に従います。

  • 0 は成功を意味します
  • 0 以外の値は異なる種類のエラーを示します
  • 他のプログラムはこれらのコードを確認して、あなたのプログラムが成功したかどうかを判断できます

29.3) os で環境変数にアクセスする

環境変数(environment variables) は、オペレーティングシステムまたはユーザーによって設定され、プログラムが読み取れるキーと値のペアです。設定、パス、API キー、その他ハードコードすべきではない設定の保存に使われます。

29.3.1) 環境変数を読み取る

os モジュールは os.environ を提供します。これは、すべての環境変数を含む辞書のようなオブジェクトです。

python
import os
 
# 特定の環境変数を取得
home = os.environ.get('HOME')  # Unix/Linux/macOS で
print(f"Home directory: {home}")
 
# 変数が存在しない場合は None を返す
api_key = os.environ.get('MY_API_KEY')
print(f"API key: {api_key}")

Output (on Linux):

Home directory: /home/alice
API key: None

デフォルト値を指定することもできます。

python
import os
 
# デフォルト値付きで環境変数を取得
log_level = os.environ.get('LOG_LEVEL', 'INFO')
print(f"Log level: {log_level}")

Output (if LOG_LEVEL not set):

Log level: INFO

29.3.2) よくある環境変数

オペレーティングシステムごとに標準的な環境変数があります。

python
import os
 
# クロスプラットフォームの変数
print("Path:", os.environ.get('PATH'))
 
# Unix/Linux/macOS
print("User:", os.environ.get('USER'))
print("Home:", os.environ.get('HOME'))
print("Shell:", os.environ.get('SHELL'))
 
# Windows
print("User", os.environ.get('USERNAME'))
print("User Profile:", os.environ.get('USERPROFILE'))
print("Temp:", os.environ.get('TEMP'))

PATH は特に重要です。実行可能プログラムを探すディレクトリの一覧が入っています。python のようなコマンドを入力すると、システムはこれらのディレクトリを検索します。

29.3.3) 環境変数を設定する

プログラムと、それが作成するサブプロセスに対して、環境変数を変更できます。

python
import os
 
# 環境変数を設定
os.environ['MY_CONFIG'] = 'production'
 
# 読み戻す
print(os.environ.get('MY_CONFIG'))  # Output: production
 
# 環境変数を削除
del os.environ['MY_CONFIG']

重要: os.environ への変更は、現在の Python プロセスと、それが起動するプログラムにのみ影響します。プログラム終了後に永続化されたり、他のプログラムに影響したりはしません。

29.4) ファイルパスとディレクトリの操作 (os.path, os.getcwd)

ファイルを扱うプログラムでは、ファイルパスを正しく扱うことが非常に重要です。osos.path モジュールは、プラットフォームに依存しない方法でパスを組み立て、操作し、問い合わせるためのツールを提供します。

29.4.1) 現在の作業ディレクトリを取得する

現在の作業ディレクトリ(current working directory) (CWD) は、相対パスを解決する際に、プログラムが起点として扱うフォルダーです。

python
import os
 
cwd = os.getcwd()
print(f"Current working directory: {cwd}")

Output (example):

Current working directory: /home/alice/projects/myapp

'data.txt' のような相対パスでファイルを開くと、Python は現在の作業ディレクトリ内を探します。CWD を理解すると、「ファイルが見つからない」エラーのデバッグに役立ちます。

29.4.2) 現在のディレクトリを変更する

os.chdir() で作業ディレクトリを変更できます。

python
import os
 
original = os.getcwd()
print("Original directory:", original)
 
# 別のディレクトリに移動
os.chdir('/tmp')
print("New directory:", os.getcwd())
 
# 元に戻す
os.chdir(original)
print("Back to:", os.getcwd())

Output:

Original directory: /home/alice/projects
New directory: /tmp
Back to: /home/alice/projects

Note: 第 28 章では、元のディレクトリを自動的に復元する contextlib.chdir() を学びました。単純なディレクトリ変更では、コンテキストマネージャ(context manager)を使うことを優先してください。

python
from contextlib import chdir
 
with chdir('/tmp'):
    print("Temporarily in:", os.getcwd())
# Automatically restored

これにより、エラーが発生した場合でも必ずディレクトリが復元されます。

29.4.3) os.path.join() でパスを組み立てる

オペレーティングシステムによってパス区切り文字が異なります。

  • Unix/Linux/macOS: / (スラッシュ)
  • Windows: \ (バックスラッシュ)

os.path.join() は、現在のプラットフォームに合った形で正しくパスを組み立てます。

python
import os
 
# サブディレクトリ内のファイルへのパスを作る
data_dir = 'data'
filename = 'users.txt'
filepath = os.path.join(data_dir, filename)
 
print(f"File path: {filepath}")

Output (on Unix/Linux/macOS):

File path: data/users.txt

Output (on Windows):

File path: data\users.txt

複数の要素を結合することもできます。

python
import os
 
base = '/home/alice'
project = 'myapp'
subdir = 'data'
file = 'config.json'
 
full_path = os.path.join(base, project, subdir, file)
print(full_path)  # Output: /home/alice/myapp/data/config.json

os.path.join() を使うと、コードをオペレーティングシステム間で移植可能にできます。

29.4.4) パスが存在するかを確認する

ファイルやディレクトリを扱う前に、それらが存在するか確認しましょう。

python
import os
 
path = 'data.txt'
 
if os.path.exists(path):
    print(f"'{path}' exists")
else:
    print(f"'{path}' does not exist")

ファイルかディレクトリかを個別に確認することもできます。

python
import os
 
path = 'mydir'
 
if os.path.isfile(path):
    print(f"'{path}' is a file")
elif os.path.isdir(path):
    print(f"'{path}' is a directory")
elif os.path.exists(path):
    print(f"'{path}' exists but is neither a file nor directory")
else:
    print(f"'{path}' does not exist")

これらのチェックにより、存在しないファイルを開こうとしたり、存在しないディレクトリを一覧表示しようとしたりする際のエラーを防げます。

29.4.5) 絶対パスを取得する

os.path.abspath() は、相対パスを絶対パスに変換します。

python
import os
 
relative_path = 'data/users.txt'
absolute_path = os.path.abspath(relative_path)
 
print(f"Relative: {relative_path}")
print(f"Absolute: {absolute_path}")

Output (example):

Relative: data/users.txt
Absolute: /home/alice/projects/myapp/data/users.txt

これはログ、エラーメッセージ、またはファイルの正確な場所を知る必要がある場合に便利です。

29.4.6) パスを要素に分割する

os.path.split() は、パスをディレクトリとファイル名に分割します。

python
import os
 
path = '/home/alice/projects/data.txt'
directory, filename = os.path.split(path)
 
print(f"Directory: {directory}")
print(f"Filename: {filename}")

Output:

Directory: /home/alice/projects
Filename: data.txt

os.path.basename() はファイル名だけを取得し、os.path.dirname() はディレクトリだけを取得します。

python
import os
 
path = '/home/alice/projects/data.txt'
 
print(f"Basename: {os.path.basename(path)}")  # Output: data.txt
print(f"Dirname: {os.path.dirname(path)}")    # Output: /home/alice/projects

29.4.7) 拡張子を分割する

os.path.splitext() は、ファイル名と拡張子を分割します。

python
import os
 
filename = 'report.pdf'
name, extension = os.path.splitext(filename)
 
print(f"Name: {name}")        # Output: report
print(f"Extension: {extension}")  # Output: .pdf

これは、ファイルの種類に基づいて処理する場合に便利です。

python
import os
 
files = ['data.csv', 'image.png', 'document.txt', 'script.py']
 
for file in files:
    name, ext = os.path.splitext(file)
    if ext == '.csv':
        print(f"Process CSV file: {file}")
    elif ext == '.png':
        print(f"Process image file: {file}")

Output:

Process CSV file: data.csv
Process image file: image.png

29.5) ファイルとディレクトリの一覧表示、作成、削除

os モジュールは、ファイルシステムを操作するための関数(function)を提供します。ディレクトリ内容の一覧表示、新しいディレクトリの作成、ファイルやフォルダーの削除などです。

29.5.1) ディレクトリ内容を一覧表示する

os.listdir() は、ディレクトリ内のすべての項目のリスト(list)を返します。

python
import os
 
# 現在のディレクトリの内容を一覧表示
contents = os.listdir('.')
print("Current directory contents:")
for item in contents:
    print(f"  {item}")

Output (example):

Current directory contents:
  script.py
  data.txt
  mydir
  README.md

このリスト(list)にはファイルとディレクトリの両方が含まれます。それらを区別するには次のようにします。

python
import os
 
contents = os.listdir('.')
print("Files:")
for item in contents:
    if os.path.isfile(item):
        print(f"  {item}")
 
print("\nDirectories:")
for item in contents:
    if os.path.isdir(item):
        print(f"  {item}")

Output:

Files:
  script.py
  data.txt
  README.md
 
Directories:
  mydir

29.5.2) ディレクトリを作成する

os.mkdir() は単一のディレクトリを作成します。

python
import os
 
new_dir = 'output'
 
if not os.path.exists(new_dir):
    os.mkdir(new_dir)
    print(f"Created directory: {new_dir}")
else:
    print(f"Directory already exists: {new_dir}")

Output:

Created directory: output

Important: 親ディレクトリが存在しない場合、os.mkdir() は失敗します。たとえば 'data' が存在しないときに 'data/output' を作ろうとすると、エラーになります。

os.makedirs() は必要な親ディレクトリをすべて作成します。

python
import os
 
nested_dir = 'data/processed/2024'
 
if not os.path.exists(nested_dir):
    os.makedirs(nested_dir)
    print(f"Created directory structure: {nested_dir}")

Output:

Created directory structure: data/processed/2024

これは、存在しなければ data、次に data/processed、次に data/processed/2024 を作成します。

29.5.3) ファイルを削除する

os.remove() はファイルを削除します。

python
import os
 
filename = 'temp.txt'
 
# 一時ファイルを作成
with open(filename, 'w') as f:
    f.write('Temporary data')
 
print(f"File exists: {os.path.exists(filename)}")  # Output: True
 
# ファイルを削除
os.remove(filename)
print(f"File exists: {os.path.exists(filename)}")  # Output: False

Warning: os.remove() はファイルを完全に削除します。ごみ箱には移動されません。

29.5.4) ディレクトリを削除する

os.rmdir() は空のディレクトリを削除します。

python
import os
 
directory = 'empty_dir'
 
# 空のディレクトリを作成してから削除
os.mkdir(directory)
print(f"Created: {directory}")
 
os.rmdir(directory)
print(f"Removed: {directory}")

os.rmdir() はディレクトリ内にファイルがあると失敗します。ディレクトリとその中身をすべて削除するには、まずファイルを削除する必要があります。

python
import os
 
def remove_directory_contents(directory):
    """ディレクトリ内のすべてのファイルを削除し、その後ディレクトリを削除します。
    
    注意: ディレクトリにサブディレクトリが含まれている場合は失敗します。
    """
    if not os.path.exists(directory):
        print(f"Directory does not exist: {directory}")
        return
    
    # ディレクトリ内のすべてのファイルを削除
    for item in os.listdir(directory):
        item_path = os.path.join(directory, item)
        if os.path.isfile(item_path):
            os.remove(item_path)
            print(f"Removed file: {item_path}")
    
    # 空になったディレクトリを削除
    os.rmdir(directory)
    print(f"Removed directory: {directory}")
 
# 使用例
test_dir = 'test_data'
os.makedirs(test_dir, exist_ok=True)
 
# テスト用ファイルをいくつか作成
with open(os.path.join(test_dir, 'file1.txt'), 'w') as f:
    f.write('test')
with open(os.path.join(test_dir, 'file2.txt'), 'w') as f:
    f.write('test')
 
# すべて削除
remove_directory_contents(test_dir)

Output:

Removed file: test_data/file1.txt
Removed file: test_data/file2.txt
Removed directory: test_data

Note: より複雑なディレクトリ削除(サブディレクトリを含む)には、Python の shutil モジュールが提供する shutil.rmtree() を使えますが、これは現時点の範囲を超えます。

29.5.5) ファイルとディレクトリの名前変更

os.rename() はファイルやディレクトリの名前を変更したり移動したりします。

python
import os
 
# ファイル名を変更
old_name = 'draft.txt'
new_name = 'final.txt'
 
# テスト用ファイルを作成
with open(old_name, 'w') as f:
    f.write('content')
 
os.rename(old_name, new_name)
print(f"Renamed '{old_name}' to '{new_name}'")

ファイルを別のディレクトリへ移動することもできます。

python
import os
 
# ディレクトリとファイルを作成
os.makedirs('source', exist_ok=True)
os.makedirs('destination', exist_ok=True)
 
with open('source/file.txt', 'w') as f:
    f.write('content')
 
# ファイルを別のディレクトリへ移動
os.rename('source/file.txt', 'destination/file.txt')
print("Moved file to destination directory")

sysos モジュールにより、Python プログラムはオペレーティングシステムと連携し、コマンドライン入力の受け取り、設定の読み取り、ファイルとディレクトリの管理ができるようになります。これらの機能は、単純なスクリプトを、より広いシステム環境とシームレスに統合される強力なコマンドラインツールへと変えます。


© 2025. Primesoft Co., Ltd.
support@primesoft.ai