- 技術 💻
chownコマンドの使い方|所有者の変更とchgrp・-Rオプション一覧
chownコマンドとは、ファイルやディレクトリの所有者(オーナー)と所有グループを変更するLinuxコマンドです。 sudo chown ユーザー名:グループ名 ファイル の形が基本で、ディレクトリの中身までまとめて変えるときは -R を付けます。グループだけを変えるコマンドが chgrp です。
この記事では、指定の書式5種類と全オプションを一覧にし、変更前後の ls -l を Ubuntu 24.04 で実際に実行して確認しました。-R とシンボリックリンクの組み合わせで変わる範囲、Operation not permitted と invalid user の再現、find と組み合わせて一部だけを変える方法、Web サーバーの公開ディレクトリや Docker ボリュームでの定番の設定、chmod との違いまで、コピーして使えるコマンドでまとめます。
検証環境は次のとおりです。
| 項目 | 内容 |
|---|---|
| OS | Ubuntu 24.04.4 LTS |
| chown / chgrp | GNU coreutils 9.4 |
| テスト用ユーザー | t151alice(UID 1001、グループ t151alice・t151dev に所属)、t151bob(UID 1002、グループ t151bob) |
| テスト用グループ | t151dev(GID 1004) |
テスト用のユーザーとグループは検証のために作成し、終了後に削除しています。プロンプトが $ の例は root で、[t151alice]$ の例は一般ユーザーで実行した結果です。一般ユーザーで所有者を変えるときは、先頭に sudo を付けます。
chownコマンドの早見表
指定の書式
| 書式 | 所有者 | グループ | 例 |
|---|---|---|---|
chown user file |
user に変更 | 変えない | chown alice report.txt |
chown user:group file |
user に変更 | group に変更 | chown alice:dev report.txt |
chown :group file |
変えない | group に変更 | chown :dev report.txt(chgrp dev と同じ) |
chown user: file |
user に変更 | user のログイングループに変更 | chown alice: report.txt |
chown UID:GID file |
番号で指定 | 番号で指定 | chown 1001:1004 report.txt |
chown --reference=基準 file |
基準ファイルと同じ | 基準ファイルと同じ | chown --reference=a.txt b.txt |
オプション一覧
| オプション | 内容 |
|---|---|
-R, --recursive |
ディレクトリの中身まで再帰的に変更する |
-v, --verbose |
処理したすべてのファイルについて結果を表示する |
-c, --changes |
実際に変更があったものだけ表示する |
-f, --silent, --quiet |
ほとんどのエラーメッセージを表示しない |
-h, --no-dereference |
シンボリックリンクそのものを変更する(リンク先は変えない) |
--dereference |
シンボリックリンクのリンク先を変更する(-R なしのときの既定) |
-H |
-R と併用。コマンドラインで指定したシンボリックリンクがディレクトリを指す場合にたどる |
-L |
-R と併用。出会ったディレクトリへのシンボリックリンクをすべてたどる |
-P |
-R と併用。シンボリックリンクをたどらない(既定) |
--from=現所有者:現グループ |
現在の所有者・グループが一致するものだけ変更する |
--reference=基準ファイル |
基準ファイルと同じ所有者・グループにする |
--preserve-root |
/ に対する再帰的な操作を止める |
--no-preserve-root |
/ を特別扱いしない(既定) |
--help / --version |
ヘルプ/バージョンを表示する |
やりたいこと別の逆引き
| やりたいこと | コマンド |
|---|---|
| 所有者だけ変える | sudo chown alice file |
| 所有者とグループを変える | sudo chown alice:dev file |
| グループだけ変える | sudo chgrp dev file または sudo chown :dev file |
| ディレクトリ以下をまとめて変える | sudo chown -R alice:dev dir |
| 変更されたものを確認しながら実行する | sudo chown -Rc alice:dev dir |
| 自分のものに戻す | sudo chown -R "$USER":"$USER" dir |
| 特定の所有者のファイルだけ変える | sudo chown -R --from=bob alice dir |
| 別のファイルと同じ所有者にする | sudo chown --reference=a.txt b.txt |
| シンボリックリンク自体を変える | sudo chown -h alice link |
| ディレクトリだけ/ファイルだけ変える | sudo find dir -type d -exec chown alice {} + |
| 現在の所有者を確認する | ls -l file、stat -c '%U:%G' file |
| 番号(UID・GID)で確認する | ls -ln file |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「chownコマンドの使い方|所有者の変更とchgrp・-Rオプション一覧」
所有者と所有グループの基本
Linux のファイルには、所有者(1人のユーザー)と所有グループ(1つのグループ)が必ず設定されています。ls -l の3列目が所有者、4列目が所有グループです。
$ ls -l report.txt
-rw-r--r-- 1 root root 0 Oct 2 10:33 report.txt
| 列 | 例 | 意味 |
|---|---|---|
| 1 | -rw-r--r-- |
種類とパーミッション(所有者・グループ・その他の順に3文字ずつ) |
| 2 | 1 |
ハードリンクの数 |
| 3 | root |
所有者 |
| 4 | root |
所有グループ |
| 5〜 | 0 Oct 2 10:33 report.txt |
サイズ、更新日時、名前 |
パーミッション(rw-r--r--)は「所有者に何を許すか」「グループに何を許すか」「その他の人に何を許すか」を決めています。つまり、chown で所有者やグループを変えると、同じパーミッションのままでも「誰がその権限を使えるか」が変わります。 ls -l の詳しい読み方は、当サイトの「lsコマンドのオプション一覧とls -lの見方|パーミッション図解」でも解説しています。
chownの書式5種類を実行結果で確認する
所有者だけを変える(user)
$ chown t151alice report.txt
$ ls -l report.txt
-rw-r--r-- 1 t151alice root 0 Oct 2 10:33 report.txt
所有者だけが t151alice に変わり、グループは root のままです。
所有者とグループを同時に変える(user:group)
$ chown t151alice:t151dev report.txt
$ ls -l report.txt
-rw-r--r-- 1 t151alice t151dev 0 Oct 2 10:33 report.txt
グループだけを変える(:group)
$ chown :t151bob report.txt
$ ls -l report.txt
-rw-r--r-- 1 t151alice t151bob 0 Oct 2 10:33 report.txt
コロンの前を省略すると、所有者は変わらずグループだけが変わります。chgrp t151bob report.txt と同じ結果です。
所有者と、そのユーザーのログイングループにする(user:)
$ chown t151bob: report.txt
$ ls -l report.txt
-rw-r--r-- 1 t151bob t151bob 0 Oct 2 10:33 report.txt
コロンの後ろを省略すると、グループは指定したユーザーのログイングループ(主グループ)になります。 user(コロンなし)ではグループが変わらず、user:(コロンあり)ではグループも変わる、という1文字の違いです。
UID・GID の番号で指定する(UID:GID)
$ chown 1001:1004 report.txt
$ ls -l report.txt
-rw-r--r-- 1 t151alice t151dev 0 Oct 2 10:33 report.txt
$ ls -ln report.txt
-rw-r--r-- 1 1001 1004 0 Oct 2 10:33 report.txt
ファイルシステムに記録されているのは名前ではなく番号(UID・GID)です。ls -l は、その番号を /etc/passwd と /etc/group で名前に変換して表示しています。ls -ln を使うと番号のまま確認できます。
番号での指定は、そのシステムに存在しないユーザーの番号でも受け付けられます。
$ chown 5000:5000 memo.txt
$ ls -l memo.txt
-rw-r--r-- 1 5000 5000 0 Oct 2 10:33 memo.txt
対応する名前がないため、ls -l に番号がそのまま表示されました。別のサーバーからコピーしたファイルや、コンテナの中で作られたファイルで番号が表示されるのは、この状態です。
ドット区切り(user.group)はコロンに置き換える
以前の書き方として user.group とドットで区切る形があります。coreutils 9.4 で試すと、変更は行われますが案内が表示されました。
$ chown t151alice.t151dev memo.txt
chown: warning: '.' should be ':': 't151alice.t151dev'
ユーザー名にドットを含められる環境もあるため、区切りはコロン(:)で書くのがおすすめです。
stat で所有者を確認する
スクリプトで所有者を取り出すには stat が便利です。
$ stat -c '%U:%G (%u:%g) %n' report.txt memo.txt
t151alice:t151dev (1001:1004) report.txt
root:root (0:0) memo.txt
| 書式 | 内容 |
|---|---|
%U / %u |
所有者の名前/UID |
%G / %g |
グループの名前/GID |
%n |
ファイル名 |
%a / %A |
パーミッションの数字/文字表記 |
-v・-cで変更内容を表示する
chown は、成功したときには何も表示しません。-v は処理したすべてのファイル、-c は実際に変わったファイルだけを表示します。
$ chown -v t151alice a.txt b.txt
changed ownership of 'a.txt' from root to t151alice
changed ownership of 'b.txt' from root to t151alice
$ chown -v t151alice a.txt
ownership of 'a.txt' retained as t151alice
$ chown -c t151alice a.txt c.txt
changed ownership of 'c.txt' from root to t151alice
$ chown -c t151bob:t151dev a.txt
changed ownership of 'a.txt' from t151alice:root to t151bob:t151dev
| メッセージ | 意味 |
|---|---|
changed ownership of 'X' from A to B |
A から B に変更した |
ownership of 'X' retained as A |
すでに A だったので変更なし(-v のみ表示) |
failed to change ownership of 'X' from A to B |
変更できなかった(-v のとき、エラーに続けて表示) |
-R と組み合わせるときは、-c を付けておくと「何が変わったか」の記録が残り、あとから確認しやすくなります。
chgrpコマンドでグループだけを変える
chgrp グループ ファイル は、所有グループだけを変えるコマンドです。chown :グループ ファイル と同じ結果になります。
$ chgrp -v t151dev b.txt
changed group of 'b.txt' from root to t151dev
$ chgrp -c 1003 b.txt
changed group of 'b.txt' from t151dev to 1003
chgrp のオプションは chown と共通で、-R、-v、-c、-f、-h、-H、-L、-P、--reference、--preserve-root が使えます(--from は chown のみです)。
| 比較 | chown | chgrp |
|---|---|---|
| 所有者の変更 | できる | できない |
| グループの変更 | できる(:group) |
できる |
| 一般ユーザーが使える場面 | 自分のファイルを、自分が所属するグループへ(:group の形) |
自分のファイルを、自分が所属するグループへ |
--from |
あり | なし |
-Rでディレクトリ以下をまとめて変更する
基本の動き
-R を付けないと、ディレクトリを指定しても変わるのはそのディレクトリだけです。
$ chown t151alice app; ls -ld app; ls -l app/README.md
drwxr-xr-x 4 t151alice root 4096 Oct 2 10:33 app
-rw-r--r-- 1 root root 0 Oct 2 10:33 app/README.md
-R を付けると、中のファイルとサブディレクトリまで変わります。-v を付けて処理の様子を表示しました。
$ chown -R -v t151alice:t151dev app
changed ownership of 'app/src/main.py' from root:root to t151alice:t151dev
changed ownership of 'app/src' from root:root to t151alice:t151dev
changed ownership of 'app/README.md' from root:root to t151alice:t151dev
changed ownership of 'app/link_file' from root:root to t151alice:t151dev
changed ownership of 'app/logs/app.log' from root:root to t151alice:t151dev
changed ownership of 'app/logs' from root:root to t151alice:t151dev
changed ownership of 'app/link_dir' from root:root to t151alice:t151dev
changed ownership of 'app' from root:root to t151alice:t151dev
同じコマンドを -c でもう一度実行すると、すでに変更済みのため何も表示されませんでした。
-R とシンボリックリンクの挙動差を実行して比べる
-R を使うときに知っておきたいのが、シンボリックリンク(別のファイルやディレクトリを指す名前)の扱いです。次の構成を用意しました。app の中に、app の外を指すリンクが2つあります。
app/
├── README.md
├── src/main.py
├── logs/app.log
├── link_dir -> ../shared (app の外のディレクトリへのリンク)
└── link_file -> ../outside.txt (app の外のファイルへのリンク)
shared/common.txt
outside.txt
app_link -> app (app を指すリンク)
すべて root:root の状態から、chown -R ... t151alice:t151dev app をオプションを変えて実行し、どこが変わったかを find -printf '%u:%g %y %p\n' で確認しました。
| 対象 | -R(既定=-P) |
-R -h |
-R -H |
-R -L |
|---|---|---|---|---|
app とその中の通常ファイル・ディレクトリ |
変わる | 変わる | 変わる | 変わる |
app/link_dir(リンク自体) |
変わる | 変わる | 変わらない | 変わらない |
app/link_file(リンク自体) |
変わる | 変わる | 変わらない | 変わらない |
shared(link_dir のリンク先) |
変わらない | 変わらない | 変わる | 変わる |
shared/common.txt(リンク先の中身) |
変わらない | 変わらない | 変わらない | 変わる |
outside.txt(link_file のリンク先) |
変わらない | 変わらない | 変わる | 変わる |
既定(-P)の実行結果です。
===== chown -R t151alice:t151dev app
t151alice:t151dev d app
t151alice:t151dev f app/README.md
t151alice:t151dev l app/link_dir
t151alice:t151dev l app/link_file
t151alice:t151dev d app/logs
t151alice:t151dev f app/logs/app.log
t151alice:t151dev d app/src
t151alice:t151dev f app/src/main.py
root:root l app_link
root:root f outside.txt
root:root d shared
root:root f shared/common.txt
-L を付けた場合です。
===== chown -R -L t151alice:t151dev app
t151alice:t151dev d app
t151alice:t151dev f app/README.md
root:root l app/link_dir
root:root l app/link_file
t151alice:t151dev d app/logs
t151alice:t151dev f app/logs/app.log
t151alice:t151dev d app/src
t151alice:t151dev f app/src/main.py
root:root l app_link
t151alice:t151dev f outside.txt
t151alice:t151dev d shared
t151alice:t151dev f shared/common.txt
既定の -R は、リンクそのものの所有者を変え、リンク先には触れません。-L を付けると、リンクをたどって app の外にある shared 以下や outside.txt まで変更します。 指定したディレクトリの外に影響が広がるため、-L は範囲を確認してから使います。迷ったら既定のまま(-P)にしておくと、変更が指定したディレクトリの中に収まります。
-H は少し意外な結果でした。引数の app はリンクではないので走査の範囲は既定と同じですが、途中で出会ったリンクについては「リンク自体」ではなく「リンク先」(shared と outside.txt)の所有者が変わっています。-H や -L を指定すると、リンクをリンク先として扱うモードになるためです。
シンボリックリンクを引数にして -R を実行した場合
もう1つ確認しておきたいのが、引数そのものがディレクトリへのリンクである場合です。
| コマンド | app_link(リンク自体) |
app とその中身 |
|---|---|---|
chown -R t151alice:t151dev app_link |
変わる | 変わらない |
chown -R t151alice:t151dev app_link/ |
変わらない | 変わる |
chown -R -H t151alice:t151dev app_link |
変わらない | 変わる |
chown t151alice:t151dev app_link(-R なし) |
変わらない | app だけ変わる |
-R でリンクを指定すると、既定ではリンクそのものだけが変更され、中身は変わりませんでした。 「-R を付けたのに中のファイルが変わっていない」という場合は、指定したパスがリンクでないかを ls -ld で確認します。末尾に / を付けるか、-H を付けると、リンク先のディレクトリが処理されます。
Web アプリの配置で current -> releases/20261002 のようなリンクを使う構成では、この違いが結果に表れます。シンボリックリンクの作り方や確認方法は「Linuxシンボリックリンクln -sの使い方|作成・削除・確認一覧」で扱っています。
-R なしでリンクを指定した場合と -h
-R を付けないときは、既定でリンク先が変わります。リンク自体を変えたいときに -h を使います。
$ chown t151alice app/link_file; ls -l app/link_file outside.txt
lrwxrwxrwx 1 root root 14 Oct 2 10:33 app/link_file -> ../outside.txt
-rw-r--r-- 1 t151alice root 0 Oct 2 10:33 outside.txt
$ chown -h t151bob app/link_file; ls -l app/link_file outside.txt
lrwxrwxrwx 1 t151bob root 14 Oct 2 10:33 app/link_file -> ../outside.txt
-rw-r--r-- 1 t151alice root 0 Oct 2 10:33 outside.txt
リンク先が存在しないリンク(リンク切れ)では、-h の有無で結果が分かれました。
$ chown t151alice dangling
chown: cannot dereference 'dangling': No such file or directory
$ chown -h t151alice dangling; ls -l dangling
lrwxrwxrwx 1 t151alice root 7 Oct 2 10:33 dangling -> nowhere
| 状況 | 変わるもの |
|---|---|
chown user link(-R なし) |
リンク先 |
chown -h user link |
リンク自体 |
chown -R user dir(dir の中のリンク) |
リンク自体 |
chown -R -L user dir(dir の中のリンク) |
リンク先とその中身 |
--preserve-root でルートへの再帰を止める
変数の展開ミスなどで / を再帰的に指定してしまう事故に備えるオプションです。
$ chown -R --preserve-root t151alice /
chown: it is dangerous to operate recursively on '/'
chown: use --no-preserve-root to override this failsafe
chown の既定は --no-preserve-root のため、スクリプトで -R を使うときは --preserve-root を明示しておくと安心です。あわせて、chown -R user "$DIR"/ のように変数を使う場合は、"${DIR:?}" と書いて変数が空のときに処理を止める方法も役立ちます。
--referenceと--fromの使い方
--reference:別のファイルと同じ所有者にする
$ ls -l a.txt c.txt
-rw-r--r-- 1 t151bob t151dev 0 Oct 2 10:33 a.txt
-rw-r--r-- 1 root root 0 Oct 2 10:33 c.txt
$ chown -v --reference=a.txt c.txt
changed ownership of 'c.txt' from root:root to t151bob:t151dev
ユーザー名を調べて打ち直す手間がなく、「隣のファイルと同じにする」「ディレクトリと同じにする」といった場面で便利です。ディレクトリを基準にして中身をそろえることもできます。
sudo chown -R --reference=/var/www/html /var/www/html/new_dir
--from:現在の所有者が一致するものだけ変える
--from=現所有者:現グループ は、条件に合うファイルだけを変更します。3つのファイルを別々の所有者にしてから試しました。
$ ls -l a.txt b.txt c.txt
-rw-r--r-- 1 root root 0 Oct 2 10:33 a.txt
-rw-r--r-- 1 t151alice t151alice 0 Oct 2 10:33 b.txt
-rw-r--r-- 1 t151bob t151bob 0 Oct 2 10:33 c.txt
$ chown -v --from=t151alice t151bob a.txt b.txt c.txt
ownership of 'a.txt' retained as root
changed ownership of 'b.txt' from t151alice to t151bob
ownership of 'c.txt' retained as t151bob
$ chown -v --from=:t151bob root: a.txt b.txt c.txt
ownership of 'a.txt' retained as root:root
ownership of 'b.txt' retained as t151bob:t151alice
changed ownership of 'c.txt' from t151bob:t151bob to root:root
| 書き方 | 条件 |
|---|---|
--from=alice |
所有者が alice |
--from=:dev |
グループが dev |
--from=alice:dev |
所有者が alice かつグループが dev |
退職や異動などで担当者が変わり、あるユーザーのファイルだけを別のユーザーへ引き継ぎたいときは、chown -R --from=旧ユーザー 新ユーザー ディレクトリ の1行で済みます。 ほかの人のファイルには触れません。
Operation not permittedとinvalid userの原因と対処
chown: changing ownership of ...: Operation not permitted
一般ユーザー t151alice で、自分のファイルの所有者を変えようとした結果です。
[t151alice]$ touch mine.txt; ls -l mine.txt
-rw-r--r-- 1 t151alice t151alice 0 Oct 2 10:34 mine.txt
[t151alice]$ chown t151bob mine.txt; echo exit=$?
chown: changing ownership of 'mine.txt': Operation not permitted
exit=1
Linux では、ファイルの所有者を変更できるのは root(正確には CAP_CHOWN という権限を持つプロセス)だけです。自分のファイルであっても、一般ユーザーは他のユーザーへ譲ることができません。 自由に譲れると、ディスク使用量の制限をすり抜けたり、他人の名義のファイルを作れたりするためです。
対処は sudo を付けることです。
sudo chown t151bob mine.txt
グループの変更は条件つきで一般ユーザーにもできる
所有グループは、自分が所有するファイルを、自分が所属しているグループへ変える場合に限り、一般ユーザーでも変更できます。
[t151alice]$ id -nG
t151alice t151dev
[t151alice]$ chgrp t151dev mine.txt; ls -l mine.txt
-rw-r--r-- 1 t151alice t151dev 0 Oct 2 10:34 mine.txt
[t151alice]$ chgrp t151bob mine.txt
chgrp: changing group of 'mine.txt': Operation not permitted
[t151alice]$ chown :t151bob mine.txt
chown: changing group of 'mine.txt': Operation not permitted
所属している t151dev へは変更でき、所属していない t151bob へは変更できませんでした。他人(ここでは root)が所有するファイルは、グループも変更できません。
[t151alice]$ ls -l roots.txt; chown t151alice roots.txt
-rw-r--r-- 1 root root 0 Oct 2 10:34 roots.txt
chown: changing ownership of 'roots.txt': Operation not permitted
[t151alice]$ chgrp t151dev roots.txt
chgrp: changing group of 'roots.txt': Operation not permitted
| 操作 | 一般ユーザー | root |
|---|---|---|
| 自分のファイルの所有者を他人に変える | できない | できる |
| 他人のファイルの所有者を自分に変える | できない | できる |
| 自分のファイルのグループを、所属するグループに変える | できる | できる |
| 自分のファイルのグループを、所属していないグループに変える | できない | できる |
| 他人のファイルのグループを変える | できない | できる |
usermod -aG でグループに追加した直後は、ログイン中のセッションにはまだ反映されていません。id -nG に新しいグループが出ない場合は、ログインし直すと反映されます。ユーザーとグループの追加手順は「Linuxユーザー追加とsudo権限付与|useradd手順と確認コマンド一覧」にまとめています。
sudo を付けても Operation not permitted になる場合
root でも変更できないケースがあります。今回の環境では再現していませんが、代表的な原因と確認方法は次のとおりです。
| 原因 | 確認方法 | 対処 |
|---|---|---|
| 変更不可(immutable)属性が付いている | lsattr ファイル に i が表示される |
sudo chattr -i ファイル で外してから変更する |
| 読み取り専用でマウントされている | findmnt -T ファイル の OPTIONS に ro |
書き込み可能な場所で作業する |
| 所有者の概念がないファイルシステム(FAT、一部のネットワーク共有など) | findmnt -T ファイル の FSTYPE |
マウント時の uid=・gid= オプションで指定する |
| コンテナやユーザー名前空間の中で、対応づけのない UID を指定した | cat /proc/self/uid_map |
ホスト側で変更する、または対応づけのある UID を使う |
| NFS の root_squash が有効 | サーバー側の設定 | サーバー側で変更する |
chown: invalid user / invalid group
存在しないユーザー名やグループ名を指定すると表示されます。
$ chown nosuchuser a.txt; echo exit=$?
chown: invalid user: 'nosuchuser'
exit=1
$ chown t151alice:nosuchgroup a.txt
chown: invalid group: 't151alice:nosuchgroup'
| 原因 | 確認・対処 |
|---|---|
| つづりの違い | getent passwd ユーザー名、getent group グループ名 で存在を確認する |
| ユーザーをまだ作っていない | sudo useradd で作成する、または UID の番号で指定する |
引数の順番が逆(chown file user) |
chown 所有者 ファイル の順にする |
| Web サーバーのユーザー名がディストリビューションで違う | Debian・Ubuntu 系は www-data、RHEL 系は apache や nginx が一般的。ps aux で実際のユーザーを確認する |
そのほかのメッセージ
| メッセージ | 意味 |
|---|---|
chown: missing operand after 'user' |
ファイルの指定がない |
chown: cannot access 'X': No such file or directory |
ファイルがない(パスを確認する) |
chown: cannot dereference 'X': No such file or directory |
リンク切れのシンボリックリンク(-h を付けるとリンク自体を変更できる) |
chown: warning: '.' should be ':' |
区切りをコロンにする |
-f を付けるとエラーメッセージは表示されなくなりますが、終了ステータスは 1 のままでした。スクリプトでは終了ステータスで成否を判定できます。
findと組み合わせて一部だけ変更する
-R は「全部」を変えます。「ディレクトリだけ」「特定の拡張子だけ」「特定の所有者のものだけ」のように条件を付けたいときは、find と組み合わせます。
検証用の構成です。
$ find site -printf '%u:%g %y %p\n' | sort -k3
root:root d site
root:root d site/cache
root:root f site/cache/x.tmp
root:root f site/config.php
root:root d site/css
root:root f site/css/style.css
root:root f site/index.html
root:root d site/uploads
root:root f site/uploads/a.png
t151bob:root f site/uploads/b.png
条件別のコマンドと実行結果
# 特定のユーザーが所有するものだけ
$ find site -user t151bob -exec chown -v t151alice {} +
changed ownership of 'site/uploads/b.png' from t151bob to t151alice
# ディレクトリだけ
$ find site -type d -exec chown -c www-data:www-data {} +
changed ownership of 'site' from root:root to www-data:www-data
changed ownership of 'site/cache' from root:root to www-data:www-data
changed ownership of 'site/uploads' from root:root to www-data:www-data
changed ownership of 'site/css' from root:root to www-data:www-data
# 拡張子が .png のファイルだけ
$ find site -type f -name '*.png' -exec chown -c www-data {} +
changed ownership of 'site/uploads/a.png' from root to www-data
changed ownership of 'site/uploads/b.png' from t151alice to www-data
# 所有者が www-data ではないものを探す(確認用)
$ find site ! -user www-data -print
site/cache/x.tmp
site/index.html
site/config.php
site/css/style.css
対応するユーザーがいないファイルを探して直す
削除済みユーザーのファイルなど、UID に対応する名前がないものは -nouser・-nogroup で探せます。
$ chown 5000:5000 site/cache/x.tmp; find site -nouser -o -nogroup
site/cache/x.tmp
$ find site -nouser -exec chown -c root:root {} +
changed ownership of 'site/cache/x.tmp' from 5000:5000 to root:root
find の条件の逆引き
| 条件 | 書き方 |
|---|---|
| 所有者が alice | -user alice |
| グループが dev | -group dev |
| UID が 1001 | -uid 1001 |
| 所有者が alice 以外 | ! -user alice |
| 対応するユーザー/グループがない | -nouser / -nogroup |
| ディレクトリだけ/ファイルだけ | -type d / -type f |
| 名前のパターン | -name '*.log' |
| 特定のディレクトリを除く | -path './node_modules' -prune -o ... -print |
| 同じファイルシステム内だけ | -xdev |
-exec は \; より + が速い
-exec ... {} \; はファイル1つごとに chown を起動し、-exec ... {} + は複数のファイルをまとめて1回の chown に渡します。空のファイル 20,000 個で時間を測りました。
| コマンド | 所要時間(real) |
|---|---|
chown -R t151alice many |
0.049 秒 |
find many -type f -exec chown root {} + |
0.069 秒 |
find many -type f -exec chown t151bob {} \; |
23.889 秒 |
\; を + に変えるだけで、この環境では約 23.9 秒が 0.07 秒になりました。 ファイル数が多いときは +(または find ... -print0 | xargs -0 chown ...)を使います。find の詳しい使い方は「findコマンドの使い方|目的別逆引き40例と-exec・xargsの違い」を参照してください。
Webサーバーの公開ディレクトリでの定番設定
Web サーバーのプロセスは、専用のユーザー(Debian・Ubuntu 系では www-data)で動いています。公開ディレクトリの所有者とグループは、「Web サーバーに何をさせたいか」で決めます。
| 方針 | 所有者:グループ | ディレクトリ | ファイル | Web サーバーができること |
|---|---|---|---|---|
| 読み取りだけ許可する(基本) | root:www-data または deploy:www-data |
750 | 640 | 読む |
| アップロード先など、書き込みが必要な場所だけ | www-data:www-data |
770 | 660 | 読む・書く |
| 全体を Web サーバーの所有にする | www-data:www-data |
755 | 644 | 読む・書く |
1つ目と2つ目を組み合わせた設定を、実際に実行して確認しました。
# 全体は root 所有・www-data グループで読み取りのみ
chown -R root:www-data site
find site -type d -exec chmod 750 {} +
find site -type f -exec chmod 640 {} +
# 書き込みが必要なディレクトリだけ www-data の所有にする
chown -R www-data:www-data site/uploads site/cache
chmod 770 site/uploads site/cache
$ ls -l site
drwxrwx--- 2 www-data www-data 4096 Oct 2 10:34 cache
-rw-r----- 1 root www-data 0 Oct 2 10:34 config.php
drwxr-x--- 2 root www-data 4096 Oct 2 10:34 css
-rw-r----- 1 root www-data 0 Oct 2 10:34 index.html
drwxrwx--- 2 www-data www-data 4096 Oct 2 10:34 uploads
www-data ユーザーとして、読み取りと書き込みを試した結果です。
$ runuser -u www-data -- bash -c 'cat /tmp/t151chown/site/index.html && echo read-ok; touch /tmp/t151chown/site/new.html; touch /tmp/t151chown/site/uploads/new.png && echo upload-ok'
read-ok
touch: cannot touch '/tmp/t151chown/site/new.html': Permission denied
upload-ok
公開ファイルは読めて、uploads にだけ書き込める状態になりました。 プログラム本体や設定ファイルを Web サーバーから書き換えられない形にしておくと、万一アプリケーションに不具合があっても影響の範囲を小さくできます。
ファイルにたどり着けないときは、途中のディレクトリの所有者とパーミッションを namei -l で一度に確認できます。
$ namei -l /tmp/t151chown/site/uploads/a.png
f: /tmp/t151chown/site/uploads/a.png
drwxr-xr-x root root /
drwxrwxrwt root root tmp
drwxr-xr-x root root t151chown
drwxr-x--- root www-data site
drwxrwx--- www-data www-data uploads
-rw-r----- root www-data a.png
複数人で編集する共有ディレクトリ(setgid)
チームで同じディレクトリを編集するときは、グループを共有用にしたうえで、ディレクトリに setgid(chmod 2775)を付ける方法が定番です。中に作られるファイルのグループが、作成者に関係なくディレクトリと同じになります。
$ mkdir team; chown t151alice:t151dev team; chmod 2775 team
$ runuser -u t151alice -- touch team/by_alice.txt; touch team/by_root.txt; ls -l team
-rw-r--r-- 1 t151alice t151dev 0 Oct 2 10:34 by_alice.txt
-rw-r--r-- 1 root t151dev 0 Oct 2 10:34 by_root.txt
root が作ったファイルも、グループは t151dev になりました。毎回 chgrp し直す手間がなくなります。
Dockerボリュームでの定番設定
コンテナでバインドマウント(ホストのディレクトリをコンテナに見せる方法)を使うと、「コンテナが作ったファイルをホストで編集できない」「コンテナから書き込めない」という場面に出会います。原因は、ファイルに記録されるのが名前ではなく UID・GID の番号で、ホストとコンテナで同じ番号が別のユーザーを指す(または対応する名前がない)ことです。先ほど chown 5000:5000 で ls -l に番号が表示されたのと同じ仕組みです。
この章のコマンドは、検証時に Docker デーモンが利用できなかったため未実行で、Docker の公式ドキュメントで確認した書き方です。
| 状況 | 定番の対処 |
|---|---|
| コンテナが root で作ったファイルをホストで編集したい | ホスト側で sudo chown -R "$(id -u):$(id -g)" ./data |
| はじめからホストのユーザーの番号で作らせたい | docker run --user "$(id -u):$(id -g)" -v "$PWD/data:/data" イメージ名 |
| コンテナ内の非 root ユーザーから書き込めない | ホスト側のディレクトリを、そのユーザーの UID・GID に chown する |
| イメージにコピーするファイルの所有者を指定したい | Dockerfile で COPY --chown=app:app . /app |
| イメージ内で実行ユーザーを切り替えたい | Dockerfile で USER app |
# Dockerfile の例(公式ドキュメントの書式に沿った形。未実行)
FROM ubuntu:24.04
RUN useradd --create-home --uid 10001 app
WORKDIR /app
COPY --chown=app:app . /app
USER app
COPY のあとに RUN chown -R app:app /app を書く方法でも同じ所有者になりますが、公式ドキュメントでは、COPY --chown を使うとコピーと所有者の指定が1つのレイヤーにまとまると説明されています。
コンテナ内で作られたファイルの番号を確認するときは、ホストで ls -ln を使うと UID・GID をそのまま見られます。
chmodとの違い
chown と chmod は役割が違い、組み合わせて使います。
| 比較 | chown | chmod |
|---|---|---|
| 変えるもの | 所有者・所有グループ(誰のものか) | パーミッション(何を許すか) |
ls -l で変わる場所 |
3列目・4列目 | 1列目 |
| 指定の例 | chown alice:dev file |
chmod 640 file |
| 一般ユーザー | 所有者の変更は不可(グループは条件つき) | 自分のファイルなら変更できる |
| 再帰 | -R |
-R |
アクセスできない原因が「権限を持つ人ではない」なら chown(または所属グループの追加)、「持つべき人に必要な権限が出ていない」なら chmod で対応します。 全員に権限を広げる chmod 777 より、所有者やグループを正しくして 750 や 640 にするほうが、必要な人だけに権限を渡せます。パーミッションの数字の意味は「chmodの755と644の意味|用途別パーミッション早見表」で解説しています。
chown すると setuid が外れる
実行ファイルに付いた setuid(所有者の権限で実行する特別なビット)は、chown を実行すると外れました。
$ cp /bin/true prog; chmod 4755 prog; ls -l prog; chown t151alice prog; ls -l prog
-rwsr-xr-x 1 root root 26936 Oct 2 10:33 prog
-rwxr-xr-x 1 t151alice root 26936 Oct 2 10:33 prog
rws が rwx に変わっています。所有者が変わったファイルが、意図せず新しい所有者の権限で実行される状態になるのを防ぐ動きです。setuid が必要なファイルは、chown のあとに chmod で付け直します。ディレクトリの setgid(drwxrwsr-x)は、chown のあとも残りました。
つまずきやすい点とチェックリスト
| 症状 | 原因 | 対処 |
|---|---|---|
-R を付けたのに中身が変わらない |
指定したパスがシンボリックリンク | 末尾に / を付ける、または -H を付ける |
| ディレクトリの外のファイルまで変わった | -L でリンクをたどった |
既定(-P)で実行する |
| 所有者は正しいのにアクセスできない | 途中のディレクトリに実行(x)権限がない | namei -l パス で確認し chmod で調整する |
| グループに追加したのに書き込めない | ログイン中のセッションに未反映 | ログインし直す |
sudo chown -R user / に近い指定をしてしまいそう |
変数が空、パスの打ち間違い | --preserve-root、"${DIR:?}" を使う |
| ホームディレクトリ以下を一括で root にしてしまった | sudo で作業した結果 |
sudo chown -R "$USER":"$USER" ~/対象 で戻す |
.ssh の鍵が使えなくなった |
所有者が本人ではない | 所有者を本人に戻し、chmod 700 ~/.ssh、chmod 600 を確認する |
直す前と後
# 直す前:全体を Web サーバーの所有にし、全員に全権限を出す
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 777 /var/www/html
# 直した後:読み取りはグループ経由、書き込みは必要な場所だけ
sudo chown -R root:www-data /var/www/html
sudo find /var/www/html -type d -exec chmod 750 {} +
sudo find /var/www/html -type f -exec chmod 640 {} +
sudo chown -R www-data:www-data /var/www/html/uploads
実行前のチェックリスト
| 確認すること | コマンド |
|---|---|
| 現在の所有者 | ls -ld パス、ls -l パス |
| 指定するユーザー・グループが存在するか | getent passwd 名前、getent group 名前 |
| パスがシンボリックリンクではないか | ls -ld パス の先頭が l でないか |
| 中にシンボリックリンクがあるか | find パス -type l |
| 対象の件数 | find パス | wc -l |
| 変更の記録を残す | chown -Rc ... | tee chown.log |
| 元に戻せるように現状を保存する | find パス -printf '%u:%g %p\n' > before.txt |
よくある質問
Q. chown と chgrp の違いは何ですか?
A. chown は所有者とグループの両方を変更でき、chgrp はグループだけを変更します。chown :dev file と chgrp dev file は同じ結果です。所有者の変更には root 権限が必要ですが、グループの変更は、自分のファイルを自分が所属するグループへ変える場合に限り一般ユーザーでも実行できます。
Q. chown で Operation not permitted と出るのはなぜですか?
A. 所有者を変更できるのは root だけのためです。自分のファイルであっても、一般ユーザーは他のユーザーへ所有者を変えられません。sudo chown ... で実行します。sudo を付けても表示される場合は、変更不可属性(lsattr で確認)、読み取り専用のマウント、所有者の概念がないファイルシステムなどが考えられます。
Q. chown -R はシンボリックリンクのリンク先も変更しますか?
A. 既定では変更しません。今回の検証では、chown -R はリンクそのものの所有者を変え、リンク先のファイルやディレクトリはそのままでした。-L を付けるとリンクをたどり、指定したディレクトリの外にあるリンク先とその中身まで変更します。
Q. 所有者を元に戻すにはどうすればよいですか?
A. chown には取り消しの機能がないため、正しい所有者を指定してもう一度実行します。自分のファイルなら sudo chown -R "$USER":"$USER" ディレクトリ で戻せます。大きな変更の前に find パス -printf '%u:%g %p\n' > before.txt で現状を保存しておくと、あとから元の状態を確認できます。
まとめ
- 書式は
user(所有者だけ)、user:group(両方)、:group(グループだけ)、user:(ログイングループも)、UID:GID(番号)の5種類 - 所有者を変更できるのは root だけ。グループは、自分のファイルを所属グループへ変える場合に一般ユーザーでも変更できる
-Rは既定でシンボリックリンク自体を変更し、リンク先には触れない。-Lを付けるとリンク先とその中身まで変わる- 引数がディレクトリへのリンクのとき、
-Rだけでは中身が変わらない。末尾に/を付けるか-Hを使う - 一部だけ変えるなら
--fromか find。-exec ... {} +は\;より大幅に速い(20,000 ファイルで 0.07 秒と 23.9 秒) -cで変更の記録を残し、--preserve-rootと"${DIR:?}"で範囲の指定ミスに備える- chown は「誰のものか」、chmod は「何を許すか」。Web の公開ディレクトリは読み取りをグループ経由にし、書き込みは必要な場所だけにする
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「chownコマンドの使い方|所有者の変更とchgrp・-Rオプション一覧」
株式会社RJCでは、chownをはじめとするLinuxの権限管理を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。