Linuxのシェルスクリプトでファイルの読み書き権限を確認する方法

シェルスクリプトでファイルを読み書きできるか確認するには、-r(読み取り)、-w(書き込み)、-x(実行/ディレクトリの検索)を使います。これは実行しているユーザーから見たアクセスの判定であり、所有者のモードビットを表示する操作とは異なります。以下ではファイルを変更しない確認例を示します。

目次

まず対象自身の権限を表示する

path="/path/to/file_or_directory"
ls -ld -- "$path"
id

ls -ldはディレクトリでも対象自身を表示します。ls -l directoryでは中の項目を一覧するため、目的が異なります。変数は必ず二重引用符で囲み、空白を含むパスを一つの引数として扱います。idで確認するユーザー・グループを確かめてください。

読み取り・書き込み・実行を個別に確認する

path="/path/to/file"

if [ -r "$path" ]; then
    printf "%s\n" "読み取り可能と判定されました"
else
    printf "%s\n" "読み取り可能とは判定されませんでした"
fi

if [ -w "$path" ]; then
    printf "%s\n" "書き込み可能と判定されました"
else
    printf "%s\n" "書き込み可能とは判定されませんでした"
fi

if [ -f "$path" ] && [ -x "$path" ]; then
    printf "%s\n" "通常ファイルで、実行権限があります"
fi

通常の-r・-w・-x・-fはシンボリックリンクの参照先を判定します。FALSEの理由は権限不足だけとは限りません。存在しないパス、途中のディレクトリを通れない場合なども確認が必要です。-fは通常ファイルかを確認します。実行権限があっても、ファイル形式・インタープリター・マウント設定などによって実際の起動に失敗する場合があります。

rootやsudoで実行すると、普段の利用者とは結果が変わることがあります。アプリや定期ジョブの問題なら、その実行ユーザーと環境で切り分けます。原因確認のためにchmod 777や再帰的な権限変更を行う必要はありません。

ディレクトリのr・w・xは意味が異なる

ディレクトリのrは中の名前一覧を読む権限、xは中を検索・通過する権限です。中のファイルへアクセスするには、パス途中のディレクトリの通過権限も関係します。ディレクトリへのwは項目の作成・削除などに関係し、通常はxも必要です。ファイル自身のwがあることと、名前変更や移動ができることは同じではありません。sticky bit、ACL、読み取り専用マウントなど追加条件も考慮します。

Bashでディレクトリ直下の通常ファイルを確認する

次はBash専用のスクリプトです。bash check-permissions.sh /path/to/directoryのように実行します。隠しファイルも含み、空ディレクトリで文字どおりの「*」を処理しないようにしています。再帰処理ではなく、指定ディレクトリの直下だけが対象です。

#!/usr/bin/env bash
set -u

dir=${1:?Usage: bash check-permissions.sh DIRECTORY}
if [[ ! -d "$dir" || ! -r "$dir" || ! -x "$dir" ]]; then
    printf '%s\n' 'ディレクトリを一覧・検索できません' >&2
    exit 1
fi

shopt -s nullglob dotglob
count=0
for file in "$dir"/*; do
    # リンク先を調べず、通常ファイルだけを対象にする
    [[ -L "$file" ]] && continue
    [[ -f "$file" ]] || continue
    r=-; w=-; x=-
    [[ -r "$file" ]] && r=r
    [[ -w "$file" ]] && w=w
    [[ -x "$file" ]] && x=x
    printf '%s%s%s  %q\n' "$r" "$w" "$x" "$file"
    count=$((count + 1))
done
printf '確認した通常ファイル: %s\n' "$count"

表示のrwxはこの処理のアクセス判定で、lsの所有者・グループ・その他の9ビット表示ではありません。シンボリックリンクは明示的に除外しています。printf %qもBashの機能で、空白や改行を含むファイル名を識別しやすく表示します。shや別のシェルでそのまま動く共通構文ではありません。

読み書きの両方が可能かを確認する

if [ -r "$path" ] && [ -w "$path" ]; then
    printf "%s\n" "読み取り・書き込み可能と判定されました"
fi

testの中で-aを使って複数条件をまとめるより、上のように個別の判定を&&でつなぐ方が意味を読み取りやすく、引数解釈の曖昧さを避けられます。

権限確認だけでmvやcpを実行しない

確認したいだけなら、条件に合うファイルを自動で移動・コピーする必要はありません。移動は元・先の親ディレクトリや上書き条件、コピーは読み取りと保存先の書き込みなど別の要件があります。-w "$file"がTRUEだから移動できる、という判定には使えません。実処理を組み込む場合は、対象を一覧で確認してから別の処理として設計します。

事前判定と実際の操作結果は別に扱う

権限の確認後、ファイルが置換されたり権限が変更されたりすることがあります。確認時にTRUEでも、直後の読み書き成功は保証されません。実際にデータを扱うプログラムでは操作そのものの終了状態を確認し、失敗を処理してください。特権を持つ処理の安全性を、先行するtestだけで保証しないことが重要です。

まとめ

対象自身の表示はls -ld、実行ユーザーからの判定は-r・-w・-xを使います。ディレクトリと通常ファイルを分け、パスを引用し、Bashの一括確認では空範囲・隠しファイル・シンボリックリンクの方針を明示します。確認と変更を分離し、権限表示だけで移動や実際の書き込み成功を保証しないようにしてください。

公式資料

GNU Coreutils:アクセス権のテスト、GNU Coreutils:権限の意味、GNU Bash:条件式

GNU Bash:ファイル名展開とnullglob・dotglob、GNU ls:-dで対象自身を表示

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次