総合演習 ― 全章の集大成
前提:7-1が完了し、nginxが公開された状態から始めます。このページでは新しいコマンドはほとんど登場しません。その代わり、1章のディレクトリ操作、2章のユーザーとyumi、3章のリダイレクト、4章のtar、5章のcron、6章のシェルスクリプトという、これまで積み上げてきたほぼ全部の技術を1本のスクリプトにまとめ上げます。題材は「yumiのホームディレクトリを毎日自動でバックアップする仕組み」です。管理者が現場で実際に組むタスクそのものだと思ってください。
SET 1〜3、合計30行のコマンドを上から順に叩きます。手打ち推奨ですが、スクリプトの中身(SET 1)は行数が多いので、綴りよりも構造を意識しながら読み書きしてください。
SET 1 ― バックアップスクリプトを書く
- $mkdir -p ~/backups
- $ls -d ~/backups
- $ls ~/scripts
- env-check.sh hello.sh loop-drill.sh
- $id yumi
- uid=1001(yumi) gid=1001(yumi) groups=1001(yumi),1002(devteam)
- $whoami
- ubuntu
- $date +%F
- 2026-07-03
- $touch ~/scripts/backup.sh
- $nano ~/scripts/backup.sh
- $cat ~/scripts/backup.sh
- #!/bin/bash
- # yumiのホームディレクトリを日付付きで圧縮保存するスクリプト
- TARGET_DIR="/home/yumi"
- BACKUP_DIR="$HOME/backups"
- TODAY=$(date +%F)
- BACKUP_FILE="$BACKUP_DIR/yumi-$TODAY.tar.gz"
- if [ ! -d "$TARGET_DIR" ]; then
- echo "エラー: $TARGET_DIR が見つかりません"
- exit 1
- fi
- if [ ! -d "$BACKUP_DIR" ]; then
- mkdir -p "$BACKUP_DIR"
- fi
- tar czf "$BACKUP_FILE" "$TARGET_DIR"
- echo "$(date '+%F %T') バックアップ完了: $BACKUP_FILE"
- $wc -l ~/scripts/backup.sh
1行目のmkdir -p ~/backupsは1-2で学んだコマンドで、バックアップファイルの保存先ディレクトリを先に作っています。2行目のls -d ~/backupsはディレクトリ自体の存在確認です(-dを付けると中身ではなくディレクトリそのものが1行表示されます)。3行目のls ~/scriptsで、6章から引き継いでいる練習スクリプトが今も残っていることを確認しておきます。4行目のid yumiは2-2でおなじみのコマンドで、バックアップ対象であるyumiが今もこのサーバーに存在していることを最終確認しています。
5行目のdate +%Fは、これから書くスクリプトの中で使う日付の書式(YYYY-MM-DD形式)を先に手元で確認しておく一言です。6行目のtouch ~/scripts/backup.shは1-2で学んだコマンドで、空のファイルを先に作っています。7行目のnano ~/scripts/backup.shで、6章で慣れ親しんだ~/scriptsの中に新しいスクリプトを作成します。8行目以降はcatでその中身を確認した出力例で、スクリプトの全文です(このページでは行数が多くなるため出力例を通常より多く表示しています)。1行目の#!/bin/bashは6-2で学んだシバン行、これから続く行をbashで実行するという宣言です。
TARGET_DIRとBACKUP_DIRは6-1で学んだ変数です。バックアップ元(yumiのホーム)と保存先を変数にしておくことで、あとから書き換えやすいスクリプトになります。TODAY=$(date +%F)は6-1で扱ったコマンド置換$()※1で、date +%F(YYYY-MM-DD形式の今日の日付)の結果を変数に代入しています。BACKUP_FILEはこれらを組み合わせて、yumi-2026-07-03.tar.gzのような日付付きのファイル名を組み立てています。
1つ目のif [ ! -d "$TARGET_DIR" ]; then ... fiは6-3で学んだ条件分岐で、-dは「ディレクトリとして存在するか」を調べるテスト演算子※2、!はその否定です。つまり「もしバックアップ元のディレクトリが存在しなかったら、エラーメッセージを出してexit 1(異常終了)する」という安全装置です。2つ目のifは、保存先~/backupsが万一なければその場で作る保険です。
最後のtar czf "$BACKUP_FILE" "$TARGET_DIR"は4-4で学んだアーカイブ作成で、c(作成)・z(gzip圧縮)・f(ファイル名指定)を組み合わせ、$TARGET_DIRを丸ごと$BACKUP_FILEという1つの圧縮ファイルにまとめます。最終行のechoは、いつ・どのファイルにバックアップが完了したかをログとして画面に出力する一言です。変数はすべてダブルクォートで囲んでいますが、これはパスの中にスペースが入っていても安全に扱えるようにする6章で学んだ書き方です。スクリプトを書き終えたら、9行目のwc -lで行数を確認しておきます(1-4で学んだ、テキストの行数を数えるコマンドでした)。
このスクリプトのように「対象があるか確認 → なければ止まる/作る → 本処理 → 結果をログに残す」という4段構えは、現場のバックアップスクリプトでもほぼそのまま使われる定番構成です。形を覚えておくと、対象やコマンドを差し替えるだけで応用が利きます。

自分のホームがバックアップされるスクリプト作ってもらえるの、なんか照れるな~。でもこれ、実際の現場だと「うっかり大事なファイル消しちゃった」を救ってくれるすごく地味だけどすごく大事な仕組みだから、ちゃんと覚えて帰ってね!
SET 2 ― 実行して確認する
- $chmod +x ~/scripts/backup.sh
- $ls -l ~/scripts/backup.sh
- -rwxr-xr-x 1 ubuntu ubuntu ... backup.sh
- $bash -n ~/scripts/backup.sh
- $./scripts/backup.sh
- tar: /home/yumi: Cannot open: Permission denied
- #sudo ~/scripts/backup.sh
- 2026-07-03 10:15:02 バックアップ完了: /home/ubuntu/backups/yumi-2026-07-03.tar.gz
- $ls -lh ~/backups
- -rw-r--r-- 1 root root 4.2K ... yumi-2026-07-03.tar.gz
- $file ~/backups/yumi-2026-07-03.tar.gz
- yumi-2026-07-03.tar.gz: gzip compressed data
- $tar tzf ~/backups/yumi-2026-07-03.tar.gz
- home/yumi/
- home/yumi/.bashrc
- $du -sh ~/backups
- $df -h /
1行目のchmod +xは6-2でおなじみ、スクリプトに実行権限を与える一言です。2行目のls -lで、出力例のように権限欄にxが加わっていることを確認します。3行目のbash -nは、スクリプトを実際には実行せず文法だけをチェックするオプションです。エラーがなければ何も表示されず、次のプロンプトに戻ります。いきなり本番実行する前に、こうした軽いチェックを挟む癖をつけておくと安心です。
4行目、あえてsudoを付けずに./scripts/backup.shを実行してみると、出力例のようにtar: /home/yumi: Cannot open: Permission deniedというエラーで止まります。バックアップ対象の/home/yumiは所有者がyumiのディレクトリで、一般ユーザーのubuntuには他人のホームディレクトリを丸ごと読み取る権限がないためです。5行目、改めてsudo ~/scripts/backup.shで実行します。tarコマンドが/home/yumiの中身を読み込むためには管理者権限が必要になるため、今度はスクリプト全体をsudoで実行しています。出力例のとおり、スクリプト内のechoの結果がそのまま画面に表示されます。
6行目のls -lh ~/backupsで、日付入りの.tar.gzファイルが実際に作られたことを確認します。sudoで実行したため、ファイルの所有者がrootになっている点にも注目してください。7行目のfileは1-4で学んだ、ファイルの種類を判定するコマンドで、出力例のようにgzip compressed dataと表示されれば圧縮ファイルとして正しく作られていることがわかります。8行目のtar tzfは4-4で学んだ、アーカイブを展開せずに中身の一覧だけを確認するオプション(t=list)です。出力例のようにhome/yumi/以下のファイルが並んでいれば、バックアップは正しく作られています。9行目のdu -shで、~/backupsディレクトリ全体のサイズを確認し、10行目のdf -h /で4-2のおさらいとしてサーバー全体のディスク使用状況も見ておきましょう。
「Permission denied」に出会ったら、まずwhoamiで自分が誰か、ls -lで相手のファイルが誰の持ち物かを確認する。この2つを合わせて考えるだけで、権限まわりのエラーの9割は原因がわかります。sudoは万能の魔法の言葉ではなく、「誰の権限で、何を読もうとしているか」を意識するための手がかりだと思ってください。
SET 3 ― cronで毎日自動化する
- $crontab -l
- no crontab for ubuntu
- #sudo crontab -l
- no crontab for root
- #sudo crontab -e
- 0 3 * * * /home/ubuntu/scripts/backup.sh
- #sudo crontab -l
- 0 3 * * * /home/ubuntu/scripts/backup.sh
- $crontab -l
- no crontab for ubuntu
- $date
- $ls ~/backups
- $tar tzf ~/backups/yumi-2026-07-03.tar.gz | head -n 3
- home/yumi/
- home/yumi/.bashrc
- $history | tail -n 5
- $cd ~
1行目でまずcrontab -lを確認すると、出力例のようにno crontab for ubuntuと表示されます。5-3で登録した練習用のcronは既に空に戻してあるため、一般ユーザーubuntuのcrontabには何も登録されていません。2行目でsudoを付けて確認しても、root用のcrontabもまだ空です。
3行目のsudo crontab -eで、5-3で学んだcronの設定を編集します。/home/yumiを読むにはroot権限が必要なので、ここでも一般ユーザーのcrontabではなくsudo crontab -e、つまりrootのcrontab※3に登録します。開いたエディタの末尾に、出力例のような1行を追記して保存します。
5フィールドの読み方は5-3のおさらいです。0 3 * * *は「分=0、時=3、日=毎日、月=毎月、曜日=毎曜日」、つまり毎日午前3時ちょうどに実行するという意味です。人がほとんどサーバーを使っていない深夜の時間帯を選ぶのは、バックアップ処理がCPUやディスクに負荷をかけている間、他の作業を邪魔しないようにするための現場の定石です。そのあとにスクリプトのパスを絶対パスで書いている※4点にも注意してください。cronは実行時に~を正しく展開してくれないことがあるため、/home/ubuntu/scripts/backup.shのようにフルパスで書くのが安全です。
4行目のsudo crontab -lは、登録した内容をその場ですぐに読み返す確認作業です。5-3でも触れたとおり、cron登録は「入れたつもり」で終わらせず、必ず-lで見直す習慣をつけましょう。5行目で試しにsudoを付けずにcrontab -lを実行すると、出力例のようにno crontab for ubuntuと表示されます。これは一般ユーザーubuntu用のcrontabと、root用のcrontabが別物として管理されているためです。今回の設定はroot側にあるので、確認するときも必ずsudoを付けます。
これで、毎日午前3時になると自動的にbackup.shが実行され、~/backupsに新しい日付のファイルが積み上がっていく仕組みが完成しました。6〜7行目は現在時刻の確認と、今日時点でのバックアップ一覧の確認です。8行目のtar tzf ... | head -n 3は4-4のtarと3-5で学んだheadの組み合わせで、アーカイブの中身の先頭数行だけをさっと覗く実務でもよく使うテクニックです。9行目のhistory | tail -n 5は1-6のhistoryと3-5のtailの組み合わせで、このページで直近に叩いたコマンドを振り返っています。10行目のcd ~でホームディレクトリに戻り、このページのドリルを締めくくります。

1章のmkdir、2章のyumiと権限、3章のリダイレクト、4章のtar、5章のcron、6章のシェルスクリプト……このスクリプト1本に、今まで叩いてきた技が全部詰まってるの気づいた? ここまで来たあなたはもう、初心者じゃなくて「サーバーを運用できる人」だよ!
まとめ
7-2では、これまでの全章で学んだコマンドを1本のバックアップ自動化スクリプトに統合しました。どの章のどのコマンドが再登場したかを振り返ります。
| コマンド/構文 | 何をするか | 初出の章 |
|---|---|---|
mkdir -p | 保存先ディレクトリを作る | 第1章 ファイル操作の基本 |
変数・$(command) | 日付やパスを組み立てる | 第6章 シェルの力 |
if [ -d ... ]; then ... fi | ディレクトリの存在を確認して分岐する | 第6章 シェルの力 |
| 所有者・sudo権限 | yumiのホームを読むための権限を扱う | 第2章 ユーザーと権限 |
tar czf / tar tzf | ディレクトリを圧縮保存・中身確認する | 第4章 システムを観察する |
chmod +x | スクリプトに実行権限を与える | 第6章 シェルの力 |
sudo crontab -e / -l | 定期実行を登録・確認する | 第5章 管理者の仕事 |
echo | 処理結果をログとして出力する | 第3章 テキスト処理 |
次のページ「7-3. yumiを見送り、サーバーを片付ける」では、このドリルで作ったものすべてを撤収し、講座を締めくくります。
- コマンド置換 …
$(コマンド)の形で、あるコマンドの実行結果を文字列として変数や別のコマンドに渡す書き方。$(date +%F)は今日の日付を文字列として取り出す。↩ - テスト演算子 …
[ ]の中で使う判定記号。-dはディレクトリとして存在するか、-fはファイルとして存在するかを調べる。↩ - rootのcrontab … 管理者権限で実行される定期タスクの一覧。一般ユーザーのcrontabとは別に管理されており、root権限が必要な処理を登録する際に使う。↩
- 絶対パスでのcron登録 … cronはユーザーがログインしたときのような環境変数(
~の展開など)を必ずしも引き継がないため、実行するスクリプトはフルパスで指定するのが安全とされる。↩