1-2. ファイル操作 - cp, mv, rm, find, ln

所要時間: 25-50分(がっつりなら2セッション分) ゴール: ファイルを「コピー・移動・削除・検索」できる。シンボリックリンクが何か分かる コミット内容: 今日の操作履歴を ~/log/linux_day02.log に保存


大前提: ファイル操作は「GUIでもできる」のになぜコマンドでやるか

Finderでドラッグ&ドロップしてもコピー・移動できます。でも:

  • 100個のファイルを「ファイル名末尾に _old を付ける」処理 → Finderだと地獄、コマンドだと1行
  • 「3日以上前に更新されたログ」だけ消す → Finderだと不可能、コマンドだと1行
  • サーバー上で操作 → そもそもFinderが無い

つまり、条件付き・大量処理・リモート の3つでコマンドが圧勝。これがバックエンドエンジニアがコマンドを離れない理由。

そして、これらの操作は 取り返しがつかない 場合がある(特に rm)。理屈を理解せず叩くと事故るので、各コマンドの「落とし穴」を意識しながら進める。


セッション①: cp / mv / rm(25-30分)

0. 録画スタート&作業ディレクトリ

mkdir -p ~/log ~/learn/linux/day02
cd ~/learn/linux/day02
script ~/log/linux_day02.log

1. cp - コピー

# 単純なコピー
cp memo.txt memo_copy.txt
 
# 別のディレクトリへコピー
cp memo.txt ~/Documents/
 
# ディレクトリごとコピー(-r が必須)
cp -r project/ project_backup/
 
# 上書き前に確認する
cp -i memo.txt other.txt
 
# 属性も保持してコピー(更新日時、権限など)
cp -p memo.txt memo_preserved.txt
 
# 全部入り(再帰+属性保持+シンボリックリンクも保持)
cp -a src/ dst/

cp (copy)の本質

ファイルを 2つに増やす コマンド。元のファイルは残る。シンプル。

ただしオプションがいくつかあって、これを使い分けないと地味に困る。

重要オプション

  • -r (recursive): ディレクトリをコピーする時に必須。-r 無しでディレクトリを cp するとエラー(「ディレクトリは無視する」と言われる)
  • -i (interactive): 上書きする前に「いいの?(y/n)」と聞いてくれる。本番では入れておきたい
  • -p (preserve): 元ファイルの更新日時・権限・所有者をそのままコピー。デフォルトだと「コピー時刻 = 今」になってしまう
  • -a (archive): -r + -p + シンボリックリンク維持。バックアップ用途の鉄板

cp の実務ユースケース

  • 設定ファイル編集前のバックアップ: cp /etc/nginx/nginx.conf{,.bak} (ブレース展開でファイル名末尾に .bak を付ける)
  • テンプレートから新規作成: cp template.html new_page.html 編集する前にコピーで雛形化
  • ディレクトリ全体の複製: cp -a project/ project_2026-05-14/(日付付きスナップショット)

cp の落とし穴

  • デフォルトは上書き確認なし: 同名ファイルがあると問答無用で上書き。-i を癖にすると安全
  • -r 忘れ: ディレクトリのコピーでエラー出たら、まず -r を疑う
  • 末尾スラッシュの罠: cp -r src/ dst/cp -r src dst/ で挙動が違う場合がある(中身だけコピー vs ディレクトリごとコピー)。慣れるまで tree dst/ で確認する癖を

2. mv - 移動・リネーム

# 移動
mv memo.txt ~/Documents/
 
# リネーム(実は移動と同じコマンド)
mv old_name.txt new_name.txt
 
# ディレクトリも -r 無しで移動できる(cp と違う!)
mv project/ ../backup/
 
# 複数ファイルを別ディレクトリへ
mv a.txt b.txt c.txt ~/archive/

mv (move)の本質と「リネーム」の謎

Unix では 「移動」と「リネーム」は同じ操作。なぜなら、ファイル名はそのファイルの「アドレス」の一部だから。

  • mv a.txt b.txt = 「a.txt を b.txt という名前のアドレスに移動」=結果としてリネーム
  • mv a.txt /tmp/ = 「a.txt を /tmp/ 配下のアドレスに移動」= 移動

同じディレクトリ内で実行すればリネーム、別ディレクトリを指定すれば移動。コマンドは1つで両方できる。

Windowsで「Rename」と「Move」が別操作なのは思想の違い(Windowsは「ファイル名はメタデータ」、Unixは「ファイル名はパスの一部」)。

mv の実務ユースケース

  • 間違って作ったファイル名を直す: mv typo.txt correct.txt
  • ログローテーション: mv app.log app.log.$(date +%Y%m%d) で日付付きログにする
  • ステージング → 本番: mv staging/new_feature.html public/feature.html

mv の落とし穴

  • 上書き確認なし: mv a.txt b.txt で既存の b.txt があると 無言で上書き-i で確認モードに
  • 空きディスク不足: 別ドライブへの mv は内部的に「コピー+削除」になる。途中で容量切れすると半端な状態に
  • ワイルドカードの罠: mv *.log /backup/ で1個もマッチしないと、変なエラーが出るかコマンド自体が失敗する

3. rm - 削除

# 単純削除
rm tmp.txt
 
# 確認しながら削除
rm -i important.txt
 
# ディレクトリを削除(-r 必須)
rm -r old_project/
 
# 確認なしで強制削除(危険)
rm -f stubborn_file.txt
 
# ディレクトリ+強制(最も危険な組み合わせ)
rm -rf old_backup/

rm (remove)の本質

ファイル/ディレクトリを 消す コマンド。シンプル。

ただし Unix のターミナルにゴミ箱は無いrm したファイルは原則として復元できない。Finder の Cmd+Delete とは違う。

-r (recursive): ディレクトリ削除に必須 -f (force): 「本当に消す?」の確認も、書き込み権限が無いファイルの警告もすべてスキップ -i (interactive): 1ファイルずつ確認

rm の実務ユースケース

  • ビルド成果物のクリーンアップ: rm -rf node_modules/ dist/
  • 古いログ削除: 後で find と組み合わせて自動化
  • 不要なバックアップを整理: rm -r project_backup_2024_*/

rm -rf / は伝説の事故コマンド

「ルートディレクトリから全部削除」= OSを破壊する。Linuxではガード機能があるが、それでも事故例は多い。

特にスクリプト内で rm -rf $PROJECT_DIR/build のような書き方をしていて、変数 $PROJECT_DIR が空文字だと:

rm -rf /build  # 実質ルート近くから消す

という事故になる。スクリプト書く時は set -u で未定義変数をエラーにするのが定石。

対策

  • alias rm='rm -i'.zshrc に書いておく(rmが常に確認モード)
  • 危険な操作の前に pwd で現在地を確認
  • ls で消す対象を先に見てから rm する
  • trash コマンド(brew install trash)でゴミ箱送りにする運用も検討

削除前の安全確認パターン

# 1. まず ls で何が消えるか目視
ls old_*
 
# 2. find で対象を絞り込んで確認
find . -name "old_*" -type f
 
# 3. 問題なければ削除
rm old_*

「ls → 確認 → rm」を癖にする。


セッション②: find / ln(25-30分)

4. find - 検索の最強コマンド

# 名前で検索(カレントディレクトリ以下)
find . -name "*.md"
 
# 大文字小文字無視
find . -iname "readme*"
 
# ディレクトリだけ
find . -type d
 
# ファイルだけ
find . -type f
 
# サイズ条件(1MB以上)
find . -size +1M
 
# 更新日時(3日以内に更新)
find . -mtime -3
 
# 見つけたものを削除
find . -name "*.tmp" -delete
 
# 見つけたものに何か実行
find . -name "*.log" -exec ls -lh {} \;

find は「検索 + 一括処理」エンジン

単なる検索コマンドではなく、条件にマッチしたファイル群に対して操作も実行できる 強力ツール。

基本構造:

find <検索場所> <検索条件> <アクション>
  • 検索場所: . (カレント)、/var/log のような絶対パスもOK
  • 検索条件: -name, -type, -size, -mtime などを組み合わせる
  • アクション: 何も指定しないと「マッチしたパスを表示」。-delete で削除、-exec で任意コマンド実行

find の主要オプション

オプション意味
-nameファイル名(パターン可)-name "*.log"
-iname大文字小文字無視の名前-iname "readme*"
-typeファイル種別-type f(ファイル)/ -type d(ディレクトリ)/ -type l(リンク)
-sizeサイズ-size +10M(10MB超)/ -size -1k(1KB未満)
-mtime更新日時-mtime -7(7日以内)/ -mtime +30(30日以上前)
-empty空のファイル/ディレクトリ(単独で使う)
-delete見つけたものを削除(条件の後に付ける)
-exec各ファイルに対してコマンド実行-exec mv {} /tmp/ \;

find の実務ユースケース

  • 巨大ファイル探し: find / -size +1G 2>/dev/null で1GB超のファイル一覧
  • 古いログの自動削除: find /var/log -name "*.log" -mtime +30 -delete(30日以上前のログ削除、cronで定期実行)
  • 特定の設定ファイルを全部見る: find /etc -name "*.conf" -type f
  • node_modules を一掃: find . -name "node_modules" -type d -prune -exec rm -rf {} +(HDD圧迫の最大要因)

find の落とし穴

  • -name はワイルドカードに引用符が必要: find . -name *.log だとシェルが *.log を先に展開してエラーになることがある。必ず "*.log" のようにクォート
  • -delete は問答無用: 確認なしで削除される。事前に -delete を外して結果を目視確認 → OKなら -delete 付けて実行、という2段階運用
  • -exec\; を忘れがち: コマンドの終わりに \; が必要(エスケープしたセミコロン)。+ で代用すると複数ファイルを一括処理できて速い
  • 検索が遅い: 巨大なディレクトリだと数十秒かかる。locate コマンド(DBベース)の方が速い場合も

パイプとの組み合わせ(次の章への布石)

find の結果を |(パイプ)で別のコマンドに渡せる:

# マッチした数を数える
find . -name "*.md" | wc -l
 
# 一覧をファイルに保存
find . -type f -mtime -1 > today_files.txt

| の仕組みは Day5: パイプとリダイレクト で詳しくやる。今は「コマンドAの結果をBに渡せる」とだけ覚えればOK

5. ln - リンクを作る

# シンボリックリンク(こっちが普段使うやつ)
ln -s ~/Documents/notes ~/notes
 
# ハードリンク
ln file.txt hardlink.txt
 
# 作ったリンクの確認
ls -l ~/notes
# lrwxr-xr-x  1 takato  staff  20 May 14 16:00 /Users/takato/notes -> /Users/takato/Documents/notes

リンクとは「ファイルへのショートカット」

1つのファイル/ディレクトリに別の名前/場所からアクセスできる仕組み。Macの「エイリアス」、Windowsの「ショートカット」と似ているが、Unix のリンクの方が機能的に統合されている。

2種類ある:

  • シンボリックリンク(symlink, ソフトリンク): 「あっちのファイル見て」という案内板。リンク先のパスを保持
  • ハードリンク: 同じファイルに別の名前を付ける(実体は1つ)

99%の場面でシンボリックリンクln -s)を使う。ハードリンクは特殊用途。

シンボリックリンク( ln -s)の本質

ln -s 元のパス リンクの名前

元のパス への案内板を リンクの名前 として作る。ls -l で見ると左端が l で、-> 元のパス と表示される。

挙動

  • リンクを開く = 元ファイルにアクセス
  • リンクを編集 = 元ファイルを編集
  • リンクを削除(rm symlink)= リンクだけ消える(元は残る)
  • 元を削除 = リンクは「壊れたリンク」になる(broken symlink)

シンボリックリンクの実務ユースケース

  • dotfiles の管理: ~/.zshrcgit clone したリポの設定ファイルへの symlink にして、設定をバージョン管理
  • 複数バージョンの切替: /usr/local/bin/python -> python3.12(バージョン切替時にリンクだけ張り替える)
  • 巨大データの参照: 別ドライブにあるデータを ~/data/ 配下から symlink で参照
  • 本番デプロイ: current/ を新リリースの symlink にして、戻したくなったら symlink を旧バージョンに張り替えるだけ(Capistrano等が使う手法)

シンボリックリンクの落とし穴

  • 相対パスと絶対パス: ln -s ./file.txt link のように相対パスで作ると、リンク自体を移動した時に壊れる。特に理由がなければ絶対パス推奨
  • cp -L でリンクを辿る: 普通の cp だとリンクのまま複製する。中身(実体)をコピーしたい場合は cp -L
  • リンク先が消えても警告ゼロ: 黙って broken に。ls -l-> /path/to/something が見えるが、その先が無い状態。readlink で確認可能
  • rm でリンク削除は安全: rm symlink してもリンク先の実体は残る。ただし rm -rf symlink_to_dir/ のように末尾スラッシュ付きで実行すると、リンク先のディレクトリ中身まで消えるので注意

ハードリンクは「めったに使わない」

同じデータに複数の名前。ディスク容量は1つ分。

制約として:

  • ディレクトリには張れない
  • 別ファイルシステム(別ドライブ)には張れない

普段使う場面はほぼない。「シンボリックリンクとは違うもの」だと知っておくだけでOK。

6. 実践課題

# 1. 練習用フォルダを準備
mkdir -p ~/learn/linux/day02/practice/{src,backup,trash}
 
# 2. ダミーファイルを作成
cd ~/learn/linux/day02/practice
touch src/file_{01..05}.txt
echo "important data" > src/important.txt
echo "old log" > src/app_2024.log
 
# 3. find で .log ファイルを探す
find . -name "*.log"
 
# 4. .log ファイルを backup/ にコピー(バックアップ)
find . -name "*.log" -exec cp {} backup/ \;
 
# 5. 確認
ls backup/
 
# 6. src/ の中身を symlink で見える化
ln -s "$(pwd)/src" ~/learn/linux/day02/src_link
ls -l ~/learn/linux/day02/src_link
 
# 7. trash/ にいらないファイルを移して、まとめて削除
mv src/file_01.txt src/file_02.txt trash/
rm trash/*
ls trash/  # 空のはず

締め: 振り返り(10分)

1. セッション録画を終了

exit

2. 今日の発見

このノートに追記:

- 一番「これ便利」だったコマンド:
- find でこういう使い方ができそう、と思ったケース:
- ヒヤッとした操作(あれば):
- 明日やりたいこと:

3. デイリーノートにコピー

デイリー/2026-05-15.md のようにテンプレを複製して記録。


チェックリスト

  • cp -r でディレクトリをコピーできた
  • mv でファイルをリネームできた
  • rm -i で確認しながら削除した
  • find . -name "*.md" で検索できた
  • ln -s でシンボリックリンクを作って ls -l で確認した
  • rm -rf の危険性を声に出して説明できる

詰まった時のチートシート

やりたいことコマンド
ファイル複製cp <元> <先>
ディレクトリ複製cp -r <元> <先>
バックアップ作成cp file.txt{,.bak}
名前変更mv <旧> <新>
移動mv <元> <先ディレクトリ>/
削除(ファイル)rm <ファイル>
削除(ディレクトリ)rm -r <ディレクトリ>
安全な削除rm -i <パス>
名前で検索find . -name "パターン"
種類で絞るfind . -type f(ファイル)/ -type d(ディレクトリ)
古いファイル探すfind . -mtime +30
シンボリックリンク作成ln -s <元の絶対パス> <リンク名>
リンク先を確認readlink <リンク>

「実務OK」基準

  • cp -r / mv / rm -r が無意識に出る
  • rm -rf の前に必ず一呼吸置く
  • find . -name "..." でファイル探しができる
  • シンボリックリンクが何かを後輩に1分で説明できる

ここまで来たら、Day3 の パーミッション に進む準備が整っている。


次のレッスン

level1_03_permissions.md をまだ生成していなければ、Claude Code に頼んで作る:

バックエンドマスター/Linux/level1_03_permissions.md を、
level1_02_file_operations.md と同じフォーマットで作って。
内容は chmod / chown / ユーザー・グループ概念 / sudo / .ssh の権限など、
権限まわりを「これは何か」「いつ使うか」「落とし穴」付きで詳しく。