hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

osモジュール,os.pathモジュールの使い方



1 はじめに

ファイルとディレクトリ操作の機能を提供するosモジュールとos.pathモジュールを使ったプログラムを作成して動作確認をしてみます。

2 検証環境

AlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

pythonの版数は以下のとおりです。

[root@server ~]# python -V
Python 3.9.16

3 osモジュールの使い方

osモジュールは、OSに依存する機能を提供するモジュールです。 ファイルやディレクトリの操作を行うことができます。osモジュールが提供する関数(一部)を以下に示します。

関数 概要
getcwd カレントディレクトリ取得する
chdir カレントディレクトリを変更する
listdir ディレクトリの中身をリストで取得する
walk ディレクトリツリーを取得する
mkdir ディレクトリを作成する
rmdir ディレクトリを削除する
makedirs ディレクトリを再帰的に作成する
rename ファイルやディレクトリの名前を変更する
chmod ファイルのパミッションを変更する

3.1 カレントディレクトリを取得、変更する方法(getcwd,chdir)

カレントディレクトリのパスを取得したあと、テストプログラムの引数に指定したパスにカレントディレクトリを変更するテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

dir = os.getcwd()
print(dir)

dir = input("ディレクトリ名を入力してください: ")
os.chdir(dir)
dir = os.getcwd()
print(dir)

テストプログラムを実行すると、カレントディレクトリを表示したあと、指定したディレクトリにカレントディレクトリを変更したことがわかります。

[root@server ~]# ./test.py
/root
ディレクトリ名を入力してください: /var/log
/var/log

3.2 ファイル一覧を取得する方法(listdir)

引数に指定したディレクトリのファイル一覧を表示するテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

dir = input("ディレクトリ名を入力してください: ")
files = os.listdir(dir)
print(files)

テストプログラムを実すると、/boot直下のファイルがリスト形式で表示されることがわかります。

[root@server ~]# ./test.py
ディレクトリ名を入力してください: /boot
['efi', 'grub2', 'loader', 'vmlinuz-5.14.0-284.11.1.el9_2.x86_64', 'System.map-5.14.0-284.11.1.el9_2.x86_64', 'config-5.14.0-284.11.1.el9_2.x86_64', '.vmlinuz-5.14.0-284.11.1.el9_2.x86_64.hmac', 'symvers-5.14.0-284.11.1.el9_2.x86_64.gz', 'initramfs-5.14.0-284.11.1.el9_2.x86_64.img', 'vmlinuz-0-rescue-ae58d7b0f9374e8d801cd68b6296a573', 'initramfs-0-rescue-ae58d7b0f9374e8d801cd68b6296a573.img', 'initramfs-5.14.0-284.11.1.el9_2.x86_64kdump.img']

リスト形式ではなく、lsコマンドを実行した時のように表示するテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

dir = input("ディレクトリ名を入力してください: ")
files = os.listdir(dir)
for file in files:
    print(file)

テストプログラムを実行すると、/boot直下のファイルがlsコマンドを実行したときのように表示されることがわかります。

[root@server ~]# ./test.py
ディレクトリ名を入力してください: /boot
efi
grub2
loader
-snip-

3.3 ディレクトリのファイルを再帰的に表示する方法(walk)

テスト用のディレクトリ、ファイルを作成します。

[root@server ~]# mkdir -p dir1/dir2
[root@server ~]# touch dir1/file1.txt
[root@server ~]# touch dir1/dir2/file2.txt

テストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

for root, dirs, files in os.walk("dir1"):
    for dir in dirs:
        print("Directory:", os.path.join(root, dir))
    for file in files:
        print("File:", os.path.join(root, file))

テストプログラムを実行します。

[root@server ~]# ./test.py
Directory: dir1/dir2
File: dir1/file1.txt
File: dir1/dir2/file2.txt

3.4 ディレクトリを作成・削除する方法(mkdir,rmdir)

引数に指定したディレクトリの作成、削除をするテストプログラムを作成します。指定したディレクトリが存在しなければ作成しますが、存在すれば作成しません。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

new_dir = input("ディレクトリ名を入力してください: ")
if os.path.exists(new_dir):
  print(f"'{new_dir}' が存在するので、作成できません")
else:
  print(f"'{new_dir}' を作成します ")
  os.mkdir(new_dir)

テストプログラムを実行します。初回実行時は/tmp/testが存在しないので、ディレクトリを作成できます。

[root@server ~]# ./test.py
ディレクトリ名を入力してください: /tmp/test
'/tmp/test' を作成します

2回目は/tmp/testが存在するので、ディレクトリが作成できないことがわかります。

[root@server ~]# ./test.py
ディレクトリ名を入力してください: /tmp/test
'/tmp/test' が存在するので、作成できません

3.5 ディレクトリを再帰的に作成する方法(makedirs)

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

new_dir = input("ディレクトリ名を入力してください: ")
if not os.path.exists(new_dir):
    os.makedirs(new_dir)
    print(f"'{new_dir}' を作成します ")
else:
    print(f"'{new_dir}' が存在するので、作成できません")
[root@server ~]# ./test.py
ディレクトリ名を入力してください: /tmp/dir1/dir2/dir3
'/tmp/dir1/dir2/dir3' を作成します

作成したディレクトリを確認します。/tmp直下にdir1/dir2/dir3が作成されていることがわかります。

[root@server ~]# ls -ld /tmp/dir1/dir2/dir3
drwxr-xr-x. 2 root root 6  9月  9 22:25 /tmp/dir1/dir2/dir3

3.6 ファイルやディレクトリの名前を変更する方法(rename)

renameはファイルやディレクトリの名前を変更する関数です。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

old_filename = input("ファイル名を入力してください: ")

with open(old_filename, "w") as file:
    file.write("0123456789\n")

with open(old_filename, "r") as file:
    old_data = file.read()
    print(f"作成したファイルの内容:{old_data}")

new_filename = input("変更後のファイル名を入力してください: ")
os.rename(old_filename, new_filename)

テストプログラムを実行します。

[root@server ~]# ./test.py
ファイル名を入力してください: old.txt
作成したファイルの内容:0123456789

変更後のファイル名を入力してください: new.txt
[root@server ~]# cat new.txt
0123456789

4 os.pathモジュールの使い方

os.path モジュールはファイルパスやディレクトリパスを操作するための関数を提供するモジュールです。

関数 概要
exists ファイルやディレクトリが存在するかどうかを確認します
dirname ファイルパスからディレクトリ名を取得する
basename ファイルパスからファイル名を取得する
splitext ファイル名から拡張子を取り出します
relpath 相対パスを取得します
abspath 相対パス絶対パスに変換します
join パスを結合します
split パス名からディレクトリ名とファイル名を取り出します

4.1 ファイルやディレクトリの存在確認する方法(exitst)

引数に指定したディレクトリ名やファイル名が存在するかどうかを確認するテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

path = input("パス名を入力してください: ")

if os.path.exists(path):
    print(f"{path} は存在します.")
else:
    print(f"{path} は存在しません.")

ディレクトリの存在確認をしてみます。

[root@server ~]# ./test.py
パス名を入力してください: /etc
/etc は存在します.

ファイルの存在確認をしてみます。

[root@server ~]# ./test.py
パス名を入力してください: /etc/chrony.conf
/etc/chrony.conf は存在します.

4.2 パス名からディレクトリ名とファイル名を取り出す方法(dirname,basename)

dirnameはパス名からディレクトリ名を取り出す関数、basenameはパス名からファイル名を取り出す関数です。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

path = input("パス名を入力してください: ")

dir = os.path.dirname(path)
file = os.path.basename(path)

print(f"dir={dir}, file={file}")

テストプログラムを実行します。パス名に/etc/chrony.confを指定すると、ディレクトリ名が/efc、ファイル名がchrony.confであることがわかります。

[root@server ~]# ./test.py
パス名を入力してください: /etc/chrony.conf
dir=/etc, file=chrony.conf

4.3 拡張子を取り出す方法(splitext)

拡張子を取りだすテストプログラムを実行します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

path = input("パス名を入力してください: ")
file_name, file_extension = os.path.splitext(path)

print(f"ファイル名:{file_name}, 拡張子:{file_extension}")

chrony.confファイルの拡張子を確認します。拡張子がconfであることがわかります。

[root@server ~]# ./test.py
パス名を入力してください: /etc/chrony.conf
ファイル名:/etc/chrony, 拡張子:.conf

カーネルモジュールの拡張子を確認します。拡張子がxzであることがわかります

[root@server ~]# ./test.py
パス名を入力してください: /usr/lib/modules/5.14.0-284.11.1.el9_2.x86_64/kernel/net/ipv4/ip_gre.ko.xz
ファイル名:/usr/lib/modules/5.14.0-284.11.1.el9_2.x86_64/kernel/net/ipv4/ip_gre.ko, 拡張子:.xz

4.4 パス名からディレクトリ名とファイル名を求めるする方法(split)

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

dir, file = os.path.split("/var/log/messages")
print(f"dir={dir}, file={file}")

テストプログラムを実行すると、/var/log/messagesからディレクトリ名(/var/log)とファイ名(messages)がそれぞれ取得できていることがわかります。

[root@server ~]# ./test.py
dir=/var/log, file=messages

4.5 パスを結合する方法(join)

joinメソッドは、引数で指定したパスを結合するメソッドです。この方法を使うと、ファイルシステムの階層構造に関する違いを気にせずにパスを作成できます。また、プラットフォーム間での互換性が確保されます。

joinメソッドの書式は以下のとおりです。

os.path.join("path1", "path2", "path3", ...)

"/"、"var"、"log”を結合するテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

log = os.path.join("/", "var", "log")
print(log)

テストプログラムを実行すると、引数に指定したパスが結合されて/var/logと表示されることがわかります。

[root@server ~]# ./test.py
/var/log

4.6 相対パス絶対パスを求める方法(relpath,abspath)

テスト用のディレクトリを作成します。

[root@server ~]# mkdir dir1/dir2/dir3

テスト用に作成したディレクトリの相対パス絶対パスを求めるテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3
import os

relative_path = "./dir1/dir2/dir3"
absolute_path = os.path.abspath(relative_path)

print(f"相対パス:{relative_path}, 絶対パス:{absolute_path}")

テストプログラムを実行すると、テスト用に作成したディレクトリの相対パス絶対パスが表示されることがわかります。

[root@server ~]# ./test.py
相対パス:./dir1/dir2/dir3, 絶対パス:/root/dir1/dir2/dir3

5 ファイルオブジェクトの使い方

5.1 read系メソッド

5.1.1 ファイル全体を読み込む方法(read)

readメソッドは、ファイル全体または指定したバイト数を読み込むためのメソッドです。readメソッドを引数なしで呼び出すとファイル全体を読み込みます。readメソッドに引数を指定すると、指定したバイト数を読み出します。

ファイル全体を読み出すテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3

with open("/tmp/test.txt", "r") as file:
    file_contents = file.read()
    print(file_contents)

テストプログラムが読み込むファイルを作成します。

[root@server ~]# vi /tmp/test.txt
[root@server ~]# cat /tmp/test.txt
111 111
222 222 222

テストプログラムを実行すると、ファイル全体読み込んでいることがわかります。

[root@server ~]# ./test.py
111 111
222 222 222

[root@server ~]#

次は、readメソッドの引数に2を指定して、ファイルから2バイトを読み込むテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3

with open("/tmp/test.txt", "r") as file:
    file_contents = file.read(2)
    print(file_contents)

テストプログラムを実行すると、ファイルから2バイト読み込んでいることがわかります。

[root@server ~]# ./test.py
11
5.1.2 ファイルから1行ずつ読み込む方法(readline)

readlineメソッドはファイルから1行ずつ読み込むためのメソッドです。ファイル終端に到達すると空文字を返します。

[root@server ~]# cat test.py
#!/usr/bin/python3

with open("/tmp/test.txt", "r") as f:
    line = f.readline()
    while line:
        print(line, end="")
        line = f.readline()

テストプログラムを実行します。

[root@server ~]# ./test.py
111 111
222 222 222
5.1.3 1行をリスト形式で取得する方法(readlines)

readlinesメソッドはファイルから全ての行を一度に読み取り、各行を文字列のリストとして返すためのメソッドです。

[root@server ~]# cat test.py
#!/usr/bin/python3

with open("/tmp/test.txt", "r") as f:
    lines = f.readlines()
    print(lines)

テストプログラムを実行します。

[root@server ~]# ./test.py
['111 111\n', '222 222 222\n']

5.2 write系メソッド

5.2.1 ファイルにデータを書き込む方法(write)

writeメソッドは、ファイルにデータを書き込むためのメソッドです。

引数に指定したファイルにデータを書き込むテストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3

file = input("ファイル名を入力してください: ")
with open(file, "w") as file:
    file.write("0123456789\n")

テストプログラムを実行して、/tmp/sample.txtを作成してみます。

[root@server ~]# ./test.py
ファイル名を入力してください: /tmp/sample.txt

作成したファイルの中身を確認します。

[root@server ~]# cat /tmp/sample.txt
0123456789

5.3 seekメソッド

seekメソッドは、ファイルオブジェクト内のカーソル位置を移動するためのメソッドです。書式は以下の通りす。

seek(offset, whence)
引数 意味
offset 移動するバイト数を指定します。正の整数値はファイルの先頭から移動し、負の整数値はファイルの末尾から逆方向に移動します
whence デフォルトは0でファイルの先頭からの相対位置を示します。1は現在の位置からの相対位置を示し、2はファイルの末尾からの相対位置を示します

テストプログラムを作成します。

[root@server ~]# cat test.py
#!/usr/bin/python3

seek = int(input("移動するバイト数を入力してください: "))
byte = int(input("読み込むバイト数を入力してください: "))

with open("/tmp/test.txt", "r") as f:
    f.seek(seek)
    data = f.read(byte)
    print(data)

テストプログラムが読み込むファイルを作成します。

[root@server ~]# vi /tmp/test.txt
[root@server ~]# cat /tmp/test.txt
0123456789

ファイル先頭から2バイト読み出してみます。

[root@server ~]# ./test.py
移動するバイト数を入力してください: 0
読み込むバイト数を入力してください: 2
01

ファイル先頭から1バイト移動してから5バイト読み出してみます。

[root@server ~]# ./test.py
移動するバイト数を入力してください: 1
読み込むバイト数を入力してください: 5
12345

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

記事作成に参考にした書籍です。

サンプルコードが短く、分かりやすいです。

Pythonコードレシピ集(Kindle版)

Pythonコードレシピ集(単行本)

  • スッキリわかるPython入門 (スッキリわかる入門シリーズ)

簡潔な説明で分かりやすいです。

スッキリわかるPython入門 (スッキリわかる入門シリーズ)(単行本)

スッキリわかるPython入門 (スッキリわかるシリーズ)(Kindle版)