touchコマンドの使い方:空ファイル作成とタイムスタンプ更新

概要

touchコマンドはファイルのタイムスタンプを更新し、存在しない場合は空ファイルを新規作成するLinux/Unix標準コマンドです。

現場では空ファイルの作成、ビルドシステムでのタイムスタンプ制御、makeの再ビルド強制、ログローテーションのトリガー、ロックファイルの作成など、多岐にわたる用途で使用します。このコマンドを知らないと、echo "" > fileのような非効率な方法で空ファイルを作成したり、タイムスタンプ操作が必要な自動化処理で手詰まりになります。シンプルですが、運用の自動化において欠かせないコマンドです。

基本コマンド・構文

空ファイルの作成

touch newfile.txt

実行結果:

$ ls -l newfile.txt
-rw-r--r-- 1 user user 0 Jan 15 10:23 newfile.txt

サイズ0バイトのファイルが作成され、タイムスタンプが現在時刻に設定されます。

既存ファイルのタイムスタンプ更新

touch existing.txt

実行前:

-rw-r--r-- 1 user user 1234 Jan 10 15:30 existing.txt

実行後:

-rw-r--r-- 1 user user 1234 Jan 15 10:25 existing.txt

ファイルサイズは変更されず、タイムスタンプのみが現在時刻に更新されます。

複数ファイルの同時作成

touch file1.txt file2.txt file3.txt

実行結果:

ls -l file*.txt
-rw-r--r-- 1 user user 0 Jan 15 10:26 file1.txt
-rw-r--r-- 1 user user 0 Jan 15 10:26 file2.txt
-rw-r--r-- 1 user user 0 Jan 15 10:26 file3.txt

すべてのファイルが同一のタイムスタンプで作成されます。

3. 現場で必須のオプション・設定

-c (–no-create) – ファイルを作成しない

touch -c maynotexist.txt

実行結果:

$ ls maynotexist.txt
ls: cannot access 'maynotexist.txt': No such file or directory

ファイルが存在しない場合、何も作成されず、エラーも出力されません。

実務での必要性:
既存ファイルのタイムスタンプのみを更新したい場合に使用します。スクリプト内で「存在すれば更新、存在しなければ何もしない」という安全な動作を実現できます。意図しない空ファイルの大量生成を防ぎ、ディスク容量の無駄遣いやinode枯渇を回避します。

-t – タイムスタンプの明示的指定

touch -t 202401151030.45 file.txt

実行結果:

$ ls -l file.txt
-rw-r--r-- 1 user user 0 Jan 15 10:30 file.txt

実務での必要性:
過去または未来の特定時刻にタイムスタンプを設定できます。形式は[[CC]YY]MMDDhhmm[.ss]です。ビルドシステムで古いタイムスタンプを設定して強制的に再ビルドをスキップさせる、テスト環境で過去のログファイルを模擬する、バックアップの整合性テストで特定時刻のファイルを再現するなど、自動化処理で頻繁に使用します。

-r (–reference) – 他ファイルのタイムスタンプをコピー

touch -r source.txt target.txt

実行前:

-rw-r--r-- 1 user user 1234 Jan 10 15:30 source.txt
-rw-r--r-- 1 user user 5678 Jan 15 10:35 target.txt

実行後:

-rw-r--r-- 1 user user 1234 Jan 10 15:30 source.txt
-rw-r--r-- 1 user user 5678 Jan 10 15:30 target.txt

target.txtのタイムスタンプがsource.txtと同じになります。

実務での必要性:
複数ファイルのタイムスタンプを揃える必要がある場合に使用します。デプロイ後に設定ファイル群のタイムスタンプを統一する、アーカイブ展開後に特定ファイルの時刻を基準ファイルに合わせるなど、ファイル管理の整合性確保に有効です。

-a – アクセス時刻のみ更新

touch -a file.txt

実行結果:

$ stat file.txt | grep Access
Access: 2024-01-15 10:40:00.000000000 +0000

更新時刻(mtime)は変更されず、アクセス時刻(atime)のみが更新されます。

実務での必要性:
ファイル内容の最終更新時刻を保持したまま、アクセス記録のみを更新したい場合に使用します。ログ監視システムで「最後にアクセスされた時刻」を基準にファイルを管理する場合や、キャッシュシステムでアクセス頻度を追跡する場合に有効です。

-m – 更新時刻のみ変更

touch -m file.txt

実行結果:

$ stat file.txt | grep Modify
Modify: 2024-01-15 10:42:00.000000000 +0000

アクセス時刻(atime)は変更されず、更新時刻(mtime)のみが更新されます。

実務での必要性:
makeやrsyncなど、mtimeを基準にファイルの新旧を判定するツールで強制的に再処理させる場合に使用します。ビルドスクリプトで特定ファイルのみを「更新された」と認識させ、依存関係を持つターゲットを再ビルドさせる際に必須です。

4. 実践的なユースケース(逆引きレシピ)

ロックファイルによる排他制御

LOCKFILE="/tmp/myscript.lock"

if ! touch "$LOCKFILE" 2>/dev/null; then
  echo "Another instance is running"
  exit 1
fi

trap "rm -f $LOCKFILE" EXIT

# メイン処理
echo "Processing..."
sleep 10

ロックファイルの存在チェックと作成をアトミックに実行し、スクリプトの多重起動を防ぎます。

makeの強制再ビルド

$ touch src/*.c
$ make

すべての.cファイルのタイムスタンプを更新し、makeに「ソースファイルが更新された」と認識させます。通常はmake clean && makeが確実ですが、クリーンビルドが時間のかかる大規模プロジェクトでは有効です。

過去のログファイルを模擬

touch -t 202312010000.00 /var/log/test/app-20231201.log
touch -t 202312020000.00 /var/log/test/app-20231202.log
touch -t 202312030000.00 /var/log/test/app-20231203.log

テスト環境でログローテーションスクリプトの動作確認を行う際、特定日付のログファイルを作成します。

バックアップファイルの一括タイムスタンプ更新

find /backup -name "*.tar.gz" -exec touch -r /backup/latest.tar.gz {} \;

latest.tar.gzのタイムスタンプをすべてのバックアップファイルにコピーします。バックアップの世代管理で基準時刻を揃える場合に使用します。

ディレクトリ構造の一括作成

mkdir -p project/{src,include,lib,bin,docs}
touch project/src/{main.c,util.c}
touch project/include/{main.h,util.h}
touch project/docs/README.md

プロジェクトの初期ディレクトリ構造と空ファイルを一括作成します。テンプレート生成スクリプトで頻繁に使用します。

古いファイルの検出テスト

# 30日前のタイムスタンプを持つテストファイル作成
touch -t $(date -d '30 days ago' +%Y%m%d%H%M) /tmp/oldfile.txt

# 7日以上前のファイルを検出するスクリプトのテスト
find /tmp -name "oldfile.txt" -mtime +7

findコマンドの-mtimeオプションの動作確認や、古いファイル削除スクリプトのテストに使用します。

Gitのタイムスタンプ復元

git ls-files | while read file; do
  timestamp=$(git log -1 --format="%ai" -- "$file")
  touch -d "$timestamp" "$file"
done

Gitでチェックアウトしたファイルのタイムスタンプを、最終コミット時刻に復元します。タイムスタンプベースのビルドシステムで、正確な依存関係を再現する場合に使用します。

5. シニアエンジニアの知恵(Expert Advice)

touchの本来の用途はタイムスタンプ更新

多くのエンジニアはtouchを「空ファイル作成コマンド」として認識していますが、本来の目的はファイルのタイムスタンプ更新です。POSIXの仕様でも、主機能はタイムスタンプの変更であり、ファイルが存在しない場合の作成は副次的な動作です。この理解があれば、-cオプションの必要性や、-a/-mの使い分けが自然に理解できます。

パーミッション継承の注意点

$ touch newfile.txt
$ ls -l newfile.txt
-rw-r--r-- 1 user user 0 Jan 15 10:50 newfile.txt

新規作成されるファイルのパーミッションは、umask値に依存します。umask 022の場合は644umask 002の場合は664になります。特定のパーミッションが必要な場合は、touch後にchmodで明示的に設定してください。

ファイルシステムの精度限界

touch -t 202401151030.45678 file.txt
stat file.txt

多くのファイルシステムは秒単位またはナノ秒単位の精度を持ちますが、指定した値が完全に保存されるとは限りません。ext4はナノ秒精度、FAT32は2秒精度です。クロスプラットフォームのスクリプトでは、この違いに注意が必要です。

touchによるディスク容量消費

# 危険: 10万個の空ファイルを作成
for i in {1..100000}; do touch file$i.txt; done

空ファイルでもinodeを消費します。ファイル数が多いと、ディスク容量が十分でもinode枯渇でファイル作成不可になります。df -iでinode使用状況を確認してください。テスト用に大量ファイルが必要な場合は、実行前にinode数を確認する習慣をつけてください。

シンボリックリンクへのtouch

ln -s target.txt link.txt
touch link.txt

デフォルトでは、リンク先のファイルのタイムスタンプが更新されます。シンボリックリンク自体のタイムスタンプを更新したい場合は、touch -h link.txtを使用します。この動作を知らないと、意図しないファイルのタイムスタンプを変更してしまいます。

makeとの組み合わせ時の注意

touch header.h
make

ヘッダーファイルのタイムスタンプを更新すると、そのヘッダーを include しているすべてのソースファイルが再コンパイルされます。大規模プロジェクトでは、1つのヘッダー更新が数百ファイルの再ビルドにつながることもあります。影響範囲を理解した上で実行してください。

タイムスタンプ形式の互換性

# GNU touchの場合
touch -d "2024-01-15 10:30:45" file.txt

# BSD touchの場合(macOS等)
touch -t 202401151030.45 file.txt

-dオプションはGNU coreutilsの拡張機能で、BSD系では使用できません。クロスプラットフォームのスクリプトでは-t形式を使用してください。-tはPOSIX標準で、すべてのUNIX系OSで動作します。

アトミック性の欠如

# 競合状態が発生する可能性
if [ ! -f "$LOCKFILE" ]; then
  touch "$LOCKFILE"
  # この間に他のプロセスが同じチェックを通過する可能性
fi

touchによるファイル作成はアトミックではありません。排他制御が必要な場合は、flockコマンドやmkdir(アトミック)を使用してください。

# より安全な排他制御
if mkdir "$LOCKDIR" 2>/dev/null; then
  trap "rmdir $LOCKDIR" EXIT
  # メイン処理
fi

mkdirはアトミック操作なので、複数プロセスが同時に実行しても、1つのプロセスのみが成功します。