Linux ファイルシステムにおけるタイムスタンプ(mtime、atime、ctime)の違い、確認方法、変更方法
はじめに
Linux OS 上で行う操作はほぼ全て「ファイル」に対して行われます。
ファイルには「作成された時」や「更新された時」の「日時」の情報が付与されています。
タイトルにある mtime 、 atime 、 ctime というのはファイルに関する日時情報にあたりますが、 なぜ 3 つあるのか? 、 それぞれどういった情報なのか? は即答が難しいです。
これら 3 つの「日時」情報を紹介します。
検証環境
$ uname -moi
x86_64 x86_64 GNU/Linux
$ head -n 2 /etc/os-release
NAME="Ubuntu"
VERSION="21.04 (Hirsute Hippo)"
$ bash -version | head -n 1
GNU bash, バージョン 5.1.4(1)-release (x86_64-pc-linux-gnu)
「タイムスタンプ」はファイル操作したときの日時情報
Linux ファイルシステムにおける日時情報のことを タイムスタンプ と呼びます。
タイムスタンプ はファイルに対して何らかの操作したときに記録されます。
ファイルが作られたタイミングでもタイムスタンプが記録されるので、「タイムスタンプが存在しない」ということはありえません。
「タイムスタンプ」はいくつかの種類がある
一口に「日時情報」といっても、Linux ファイルシステムには以下の 3 つの「タイムスタンプ」があり、 更新されるタイミングが異なります。
- mtime : 中身(コンテンツ)が変更された日時
- atime : アクセスされた日時
- ctime : 属性が変更された日時
mtime は比較的わかりやすいですが、他のものがわかりにくいです。
具体例をもとにそれぞれのタイムスタンプの変化を見ていきましょう。
タイムスタンプを確認するには?
タイムスタンプを確認する方法はいくつかあります。
ls -l
コマンド ( mtime を確認 )
ls -l
コマンドでファイルの一覧を表示できますが、この際に表示されるタイムスタンプは mtime となります。
# file1.txt というファイルを作成
$ date > file1.txt
$ ls -l
合計 4
-rw-r--r-- 1 root root 43 1月 6 17:23 file1.txt
ls -lu
コマンド ( atime を確認 )
ls -l
コマンドに更に u
オプションを付与すると、 atime タイムタンプが表示されます。
$ ls -lu
合計 4
-rw-r--r-- 1 root root 43 1月 6 17:23 file1.txt
ls -l
の実行結果と全く一緒なので、違うタイムスタンプが表示されているかわかりませんね。
試しに atime を変更してみましょう。
先に説明した通り、 atime とは アクセスされた日時 のことでした。
そこで内容は変更せず、ファイルの内容の確認だけを行ってみましょう。
# cat コマンドでファイルの内容を参照する
$ cat file1.txt
2022年 1月 7日 月曜日 17:23:48 JST
# mtime を確認
$ ls -l
合計 4
-rw-r--r-- 1 root root 43 1月 6 17:23 file1.txt
# atime を確認
$ ls -lu
合計 4
-rw-r--r-- 1 root root 43 1月 6 17:26 file1.txt
このように、atime はファイルの内容を読み込んだ場合に更新されます。
atime をもう少し詳しく解説
実は、 atime の挙動はもう少し複雑です。
/etc/fstab
にて「ファイルシステムがどのようなオプション付きでマウントされているか」によって挙動が変わります。
# atime はファイルアクセス時に「常に更新される」
$ cat /proc/mounts | grep 'atime'
/dev/root / ext4 rw,strictatime 0 0
# atime はファイルアクセス時に「常に更新されない」
$ cat /proc/mounts | grep 'atime'
/dev/root / ext4 rw,noatime 0 0
# atime はファイルアクセス時に「条件(後述)を満たした場合」に更新される
$ cat /proc/mounts | grep 'atime'
/dev/root / ext4 rw,relatime 0 0
多くの場合、 relatime オプションが有効になっています。
relatime が設定されているファイルシステムでは、以下のいずれかの条件を満たした場合のみ atime が更新されます。
- mtime よりも古い
- ctime よりも古い
- 現在時刻-24 時間 よりも古い
ls
コマンドや du
コマンドでは更新されません。ファイルサイズもブロックサイズなどから算出しているためだと思います。
vi
や sed
で更新する場合は mtime だけでなく atime も更新されてしまいますが、これは内部的に更新する前に読み込みを行っているためでしょう。
このように atime は思わぬタイミングで更新される可能性があります。
ついでに mtime も変更してみましょう。
ファイルの末尾に文字列を「追記」してみます。
$ date >> file1.txt
# mtime を確認
$ ls -l
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:28 file1.txt
# atime を確認
$ ls -lu
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:26 file1.txt
ファイルの末尾に文字列を追記しただけの場合は、mtime だけが更新され、atime は更新されません。
また、 ls
コマンドでファイルの属性情報(≠ 中身)を参照しただけでは、atime は更新されません。
# file1.txt に対して ls コマンドを実行する(ファイルの「中身」を参照しているわけではない)
$ ls -l file1.txt
-rw-r--r-- 1 root root 86 1月 6 17:28 file1.txt
# atimeは更新されない
$ ls -lu
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:26 file1.txt
ls -lc
コマンド ( ctime を確認 )
ls -l
コマンドに更に c
オプションを付与すると、 ctime タイムタンプが表示されます。
$ ls -lc
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:28 file1.txt
表示されたタイムスタンプは mtime と同じ値となっているので ctime が表示されたのかわかりません。
試しに ctime を変更してみましょう。
先に説明した通り、 ctime とは 属性が変更された日時 のことでした。
そこで、ファイルの「属性」情報を変更してみましょう。
「属性」といえば、パーミッション、パーミッション変更といえば chmod
ですね。
chmod
実行前の mtime、 atime、ctime と 実行後の mtime、atime、ctimme を表示してみます。
# ***** chmod 実行前 *****
# mtime を確認
$ ls -l
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:28 file1.txt
# atime を確認
$ ls -lu
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:26 file1.txt
# ctime を確認
$ ls -lc
合計 4
-rw-r--r-- 1 root root 86 1月 6 17:28 file1.txt
$ chmod 666 file1.txt
# ***** chmod 実行後 *****
# mtime を確認
$ ls -l
合計 4
-rw-rw-rw- 1 root root 86 1月 6 17:28 file1.txt
# atime を確認
$ ls -lu
合計 4
-rw-rw-rw- 1 root root 86 1月 6 17:26 file1.txt
# ctime を確認
$ ls -lc
合計 4
-rw-rw-rw- 1 root root 86 1月 6 18:08 file1.txt
chmod
で変更されたのは、 ctime だけだったのがわかります。
ファイルの内容を変更する場合は、 mtime が変更されるため、「内容」とともに「属性」情報も変更されます。
そのため、 ctime も同時に変更されます。
$ ls -l
合計 4
-rw-rw-rw- 1 root root 86 1月 6 17:28 file1.txt
$ ls -lc
合計 4
-rw-rw-rw- 1 root root 86 1月 6 18:08 file1.txt
$ echo hello >> file1.txt
$ ls -l
合計 4
-rw-rw-rw- 1 root root 92 1月 6 18:12 file1.txt
$ ls -lc
合計 4
-rw-rw-rw- 1 root root 92 1月 6 18:12 file1.txt
stat
コマンド
ここまで ls
コマンドでそれぞれのタイムスタンプ情報を確認してきました。
- mtime :
ls -l
で確認 - atime :
ls -lu
で確認 - ctime :
ls -lc
で確認
3 つのタイムスタンプを確認するために 3 回もコマンド実行するのは面倒です。
ファイルのメタ情報 (タイムスタンプを含む) をまとめて確認する場合は、 stat
コマンドを利用します 。
$ stat file1.txt
File: file1.txt
Size: 92 Blocks: 8 IO Block: 4096 通常ファイル
Device: 100014h/1048596d Inode: 3036699 Links: 1
Access: (0666/-rw-rw-rw-) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-01-06 17:26:04.908323000 +0900
Modify: 2022-01-06 18:12:58.535283000 +0900
Change: 2022-01-06 18:12:58.535283000 +0900
Birth: 2022-01-06 17:23:48.085993000 +0900
Access が atime、 Modify が mtime、 Change が ctime に該当します。
3 つのタイムスタンプの他に、 Birth 、つまり作成日時も確認できます。
ただし、 Birth が表示されるかどうかは利用しているファイルシステムによって異なり、表示されない場合もあるためあまり期待はできない属性情報です。
まとめ
mtime、atime、ctime の更新タイミングと確認方法は以下の表に表現できます。
タイムスタンプ | 「内容」を変更 | 「属性」を変更 | 「内容」を参照 | タイムスタンプを確認 |
---|---|---|---|---|
mtime | 更新 | - | - | stat / ls -l |
atime | - | - | 更新(ファイルシステムの設定による) | stat / ls -lu |
ctime | 更新 | 更新 | - | stat / ls -lc |
おまけ : touch
コマンドで atime
、 mtime
を更新する
touch
コマンドを使って、 任意の時刻に atime
や mtime
を更新できます。
実際にファイルを用意して、 atime や mtime を更新してみます。
# まずはファイルを作成
$ touch file2.txt
# ファイルのタイムスタンプを確認
$ stat file2.txt
File: file2.txt
Size: 0 Blocks: 0 IO Block: 4096 通常の空ファイル
Device: 100014h/1048596d Inode: 3036698 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-02-07 19:39:37.176322000 +0900
Modify: 2022-02-07 19:39:37.176322000 +0900
Change: 2022-02-07 19:39:37.176322000 +0900
Birth: 2022-02-07 19:39:37.176322000 +0900
# before-stat というファイルに書き出しておく(あとで diff してみる)
$ stat file2.txt > before-stat
それでは atime を "2022-02-05 13:00" に更新してみます。
touch
コマンド実行時に、 -a
、 -t
オプションを指定します。
# atime を更新
$ touch -a -t 02051300 file2.txt
# stat の実行結果と diff する
$ stat file2.txt > after-stat
$ diff before-stat after-stat
5c5
< Access: 2022-02-07 19:39:37.176322000 +0900
---
> Access: 2022-02-05 13:00:00.000000000 +0900
7c7
< Change: 2022-02-07 19:39:37.176322000 +0900
---
> Change: 2022-02-07 19:40:38.784894000 +0900
>
で始まる部分が変更後のタイムスタンプです。
atime だけを更新するつもりが、 ctime も同時に更新されました 。
今度は mtime を "2022-02-05 14:00" に更新してみます。
touch
コマンド実行時に、 -m
、 -t
オプションを指定します。
# mtime を更新
$ touch -m -t 02051400 file2.txt
$ stat file2.txt > after2-stat
$ diff after-stat > after2-stat
6,7c6,7
< Modify: 2022-02-07 19:39:37.176322000 +0900
< Change: 2022-02-07 19:40:38.784894000 +0900
---
> Modify: 2022-02-05 14:00:00.000000000 +0900
> Change: 2022-02-07 19:44:38.329516000 +0900
mtime だけを更新するつもりが、 ctime も同時に更新されました 。
mtime 、 atime ともに、 touch
コマンドで改ざんできます。
ただし、 touch
コマンドでは ctime を変更できません。
そこで、 なにか変更が行われたのでは?と思ったら、ctime を見ておくのが良さそうです 。
ひとこと
数年前からいつかブログネタに整理したいと思っていたことがようやく投稿できました。
ディスカッション
コメント一覧
まだ、コメントがありません