Linux

使えなきゃヤバいLinux基礎コマンド(pwd, rm, mkdir, rmdir)

pwdは現在地、mkdirは作成、rmdirは空ディレクトリの削除、rmは中身ごと削除。4つの役割の違いと、-p / -r / -f / -d などよく使うオプションを、GNU coreutilsの記述に沿ってまとめます。

ディレクトリまわりの基礎コマンド4つ、pwd / mkdir / rmdir / rm のメモです。毎回 man を開くのも面倒なので、自分が引き直したくなる範囲だけ置いておきます。

記述はすべて GNU Coreutils マニュアル(9.11)に合わせています。macOS の標準コマンドは BSD 版なのでオプションが違うところがあります。そこは後述します。

4つの役割を1行で
  • pwd … いま自分がどこにいるかを表示する
  • mkdir … ディレクトリを作る
  • rmdir … 空のディレクトリだけ消す
  • rm … ファイルを消す。-r を付けると中身ごと消す

pwd — いまどこにいるのか

カレントディレクトリの絶対パスを表示します。引数なしで打つのがほとんどですが、シンボリックリンクをまたいでいるときだけ挙動が2種類あります。

OptionDescription
-L / --logical環境変数 PWD の値をそのまま出す。シンボリックリンクをたどってきた見かけ上の道順が残る
-P / --physicalシンボリックリンクをすべて解決した実体のパスを出す

-L と -P を両方書いた場合は、後に書いたほうが優先されます。

ハマりどころ:既定値が「どの pwd か」で逆になります

GNU coreutils の /bin/pwd は、オプションなしのとき -P(実体パス)が既定です(POSIXLY_CORRECT が設定されている場合を除く)。一方 bash などのシェルには pwd が組み込みコマンドとして入っていて、そちらは -L(見かけ上のパス)が既定です。

つまり普通にターミナルで pwd と打つと、動いているのはシェル組み込みのほうです。マニュアル本体も「シェルのエイリアスや組み込み関数のせいで、ここに書いた挙動と違うものが得られることがある」と明記していて、切り分けたいときは env pwd で呼べと案内しています。

# 組み込みの pwd(既定 -L)と実体の pwd(既定 -P)を並べて確認する
pwd
env pwd

mkdir — ディレクトリを作る

指定した名前のディレクトリを、書いた順に作ります。すでに存在する名前を指定するとエラーになります(-p を付けていて、かつそれがディレクトリの場合を除く)。

OptionDescription
-p / --parents途中の親ディレクトリがなければまとめて作る。すでにあってもエラーにしない
-m mode / --mode=mode作るディレクトリのパーミッションを指定する。書式は chmod と同じ
-v / --verbose作成したものを1件ずつ表示する
# src と src/lib と src/lib/util をまとめて作る
mkdir -p src/lib/util

# すでにあってもエラーにならないので、スクリプトの中ではこれが安全
mkdir -p /var/log/myapp
ハマりどころ:-m は -p で作られた親には効きません

マニュアルは「このオプションはコマンドラインで与えられたディレクトリにのみ効き、-p によって作られる親には影響しない」と書いています。mkdir -p -m 700 a/b/c としたとき、700 になるのは c だけで、a と b は umask に従った通常の権限で作られます。

親も含めて権限を締めたいなら、作ってから chmod をかけ直すことになります。

権限の指定そのものについては chmodとchownの記事のほうに書いています。

rmdir — 空のディレクトリだけ消す

rmdir は空のディレクトリを削除します。中身が残っているとエラーになって消えません。

OptionDescription
-p / --parents指定したディレクトリを消したあと、その親も順に消していく。rmdir -p a/b/c は rmdir a/b/c a/b a とほぼ同じ
--ignore-fail-on-non-empty「空じゃないので消せなかった」という失敗を無視する。エラー表示も出ず、終了ステータスも失敗にならない
-v / --verbose削除できたものを1件ずつ表示する

-p は途中のどれかが空でなければそこで失敗します。「消せるところまで消して、あとは黙って諦めてほしい」という使い方をしたいときに --ignore-fail-on-non-empty を併せます。

# c → b → a の順に、空である限り消していく
rmdir -p a/b/c

# 空でないディレクトリに当たっても静かに終わる
rmdir -p --ignore-fail-on-non-empty a/b/c
rm -r があるのに rmdir が残っている理由

「空のときしか消えない」という制約が、そのまま安全装置になっているからですね。中身が残っていることに気づかないまま消してしまう事故が、rmdir では原理的に起きません。空のはずだと思っているものを片付けるときは、rm -r ではなく rmdir を使うほうが安全です。

ちなみに、配下の空ディレクトリを全部まとめて掃除したい場合、マニュアルは find を使う方法を案内しています。

# GNU 拡張を使う書き方
find dirname -type d -empty -delete

# POSIX 環境ならこちら
find dirname -depth -type d -exec rmdir {} +

rm — 消す。そして戻せない

ファイルを削除します。ゴミ箱に入るわけではないので、実行した時点で戻せません。ここだけはオプションの意味を覚えておいたほうがいいです。

OptionDescription
-r / -R / --recursiveディレクトリを中身ごと再帰的に消す
-d / --dir空のディレクトリを消す。rmdir 相当の動き
-f / --force存在しないファイルを無視し、確認も出さない。安全装置を外すオプション
-i1件ずつ消していいか確認する
-Iファイルが3つより多いとき、または再帰削除のときに、まとめて1回だけ確認する
-v / --verbose消したものを1件ずつ表示する

-i は件数が多いと確認が終わらなくなるので、実運用だと -I のほうが現実的です。「うっかり広い範囲を指定してしまった」という一番危ない事故を、1回の確認で止められます。

rm -rf / は既定で止まります(ただし過信しないこと)

GNU coreutils の rm には --preserve-root があり、マニュアルは --recursive と一緒に使われたときにルートディレクトリ / の削除を拒否する、そしてこれが既定の挙動であると書いています。

止まるのは / そのものを指定した場合です。rm -rf /home/user/ のつもりで変数が空になり rm -rf /home// になった、というような事故はこの防護の外側で普通に通ります。守ってくれるのは最後の一線だけ、くらいに思っておくのがよさそうです。

もうひとつ、ハイフンで始まる名前のファイルはオプションと区別がつかず消せません。-- でオプションの終わりを示すか、パスの形にして渡します。

# -f という名前のファイルを消す
rm -- -f
rm ./-f

macOS で違うところ

macOS 標準の rm / mkdir は BSD 版なので、GNU 版のオプションがそのままは通らないことがあります。手元で確認できた範囲だと以下です。

コマンド状況
rm -IBSD 版にもあり、同じくまとめて1回確認する
rm --preserve-rootBSD 版にはない。ロングオプション自体が使えない
rmdir --ignore-fail-on-non-emptyBSD 版にはない
mkdir -p / -m / -v同じように使える

GNU 版に揃えたい場合は Homebrew の coreutils を入れると、grm / gmkdir のように g 付きの名前で GNU 版が入ります。とはいえ、そこまでやるくらいなら素直に Linux 側で作業したほうが早い気もします。

まとめ

やりたいことコマンド
いまどこにいるか知りたいpwd
シンボリックリンクの実体を知りたいpwd -P または env pwd
深い階層をまとめて作りたいmkdir -p a/b/c
空のはずのディレクトリを消したいrmdir(空でなければ止まる)
中身ごと消したいrm -r
広い範囲を消すとき事故りたくないrm -Ir

4つのうち3つは「作る・消す」で、残り1つの pwd だけが「確認する」コマンドです。事故るのはだいたい現在地を勘違いしているときなので、消す前に pwd、という順番だけ守っておけば大体なんとかなります。なんとかならなかったことも普通にあるんですが。

参考資料

関連するLinuxの基礎メモ