シェルスクリプトとは?書き方の基本・シバン・実行方法から変数・制御構文まで解説

スクリプト設計

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

    1. Q3. `sh script.sh` と `./script.sh` は何が違う?
  1. まとめ
    1. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    2. Q3. `sh script.sh` と `./script.sh` は何が違う?
  2. まとめ
  3. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  4. まとめ
    1. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  5. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  6. まとめ
    1. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    2. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  7. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  8. まとめ
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  9. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  10. まとめ
  11. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  12. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  13. まとめ
    1. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  14. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  15. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  16. まとめ
    1. サンプル2:ファイルの一括リネーム(拡張子変更)
    2. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  17. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  18. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  19. まとめ
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  20. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  21. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  22. まとめ
  23. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  24. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`”$VAR”`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  25. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  26. まとめ
  27. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  28. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  29. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  30. まとめ
    1. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  31. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  32. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  33. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  34. まとめ
    1. 3. 繰り返し処理:`for` 文
    2. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  35. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  36. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  37. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  38. まとめ
    1. 2. 条件分岐:`case` 文(多岐分岐)
    2. 3. 繰り返し処理:`for` 文
    3. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  39. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  40. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  41. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  42. まとめ
    1. 2. 条件分岐:`case` 文(多岐分岐)
    2. 3. 繰り返し処理:`for` 文
    3. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  43. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  44. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  45. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  46. まとめ
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  47. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  48. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  49. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  50. まとめ
  51. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  52. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  53. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  54. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  55. まとめ
    1. 3. クォーテーション(引用符)とコマンド置換
  56. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  57. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  58. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  59. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  60. まとめ
    1. 2. 特殊変数と位置引数(引数の受け取り)
    2. 3. クォーテーション(引用符)とコマンド置換
  61. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  62. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  63. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  64. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  65. まとめ
    1. 1. 変数の定義と参照
    2. 2. 特殊変数と位置引数(引数の受け取り)
    3. 3. クォーテーション(引用符)とコマンド置換
  66. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  67. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  68. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  69. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  70. まとめ
    1. ステップ4:スクリプトの実行(`./` の指定)
  71. シェルスクリプトの基本文法(変数・引数・クォート)
    1. 1. 変数の定義と参照
    2. 2. 特殊変数と位置引数(引数の受け取り)
    3. 3. クォーテーション(引用符)とコマンド置換
  72. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  73. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  74. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  75. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  76. まとめ
  77. シェルスクリプトとは?(役割とメリット)
    1. 「シェル」と「シェルスクリプト」の違い
    2. シェルスクリプトを導入する3つの大きなメリット
  78. シェルスクリプトの作成から実行までの4ステップ
    1. ステップ1:テキストファイルの作成(拡張子は `.sh`)
    2. ステップ2:シバン(Shebang)とコマンドの記述
    3. ステップ3:実行権限の付与(`chmod +x`)
    4. ステップ4:スクリプトの実行(`./` の指定)
  79. シェルスクリプトの基本文法(変数・引数・クォート)
    1. 1. 変数の定義と参照
    2. 2. 特殊変数と位置引数(引数の受け取り)
    3. 3. クォーテーション(引用符)とコマンド置換
  80. 制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)
    1. 1. 条件分岐:`if` 文
    2. 2. 条件分岐:`case` 文(多岐分岐)
    3. 3. 繰り返し処理:`for` 文
    4. 4. 繰り返し処理:`while` 文(ファイルの1行読み込み)
  81. 実務で役立つ!実践サンプルコード3選
    1. サンプル1:ログファイルの自動バックアップ&圧縮スクリプト
    2. サンプル2:ファイルの一括リネーム(拡張子変更)
    3. サンプル3:引数チェック&エラー処理付きの安全スクリプト
  82. バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス
    1. 1. 冒頭に `set -euo pipefail` を記述する(厳格モード)
    2. 2. 変数は常にダブルクォートで囲む(`"$VAR"`)
    3. 3. 事前文法チェック(`bash -n`)と ShellCheck の活用
  83. よくあるトラブルとFAQ
    1. Q1. `Permission denied` と表示されて実行できない
    2. Q2. `\r: command not found` や `syntax error near unexpected token` と出る
    3. Q3. `sh script.sh` と `./script.sh` は何が違う?
  84. まとめ
  85. 関連記事

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`”$VAR”`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

スクリプト実行時に外部から渡された引数は、位置引数(Positional Arguments)として参照できます。

変数名意味・役割
$0実行されたスクリプト自体の名前(ファイル名)
$1, $2, $3第1引数、第2引数、第3引数...
$#渡された引数の総数
$@渡された全引数のリスト("$@" で個別にクォート保持)
$?直前に実行されたコマンドの**終了ステータス**(0は成功、非0は失敗)
$$現在のシェルスクリプトのプロセスID(PID)

位置引数の活用サンプル:

#!/usr/bin/env bash

echo "実行スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "引数の総数: $#"

# 直前コマンドの成功確認
ls "$1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "ディレクトリ $1 は存在します。"
fi

3. クォーテーション(引用符)とコマンド置換

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

シェルスクリプトでの変数定義は 変数名=値 の形式で行います。

#!/usr/bin/env bash

# 変数の定義(=の左右にスペースを入れてはいけない)
TARGET_DIR="/var/log"
SERVER_NAME="web-01"

# 変数の参照($を付ける。${}で囲むと境界が明確になる)
echo "バックアップ対象: ${TARGET_DIR}"
echo "対象サーバー: $SERVER_NAME"

注意: TARGET_DIR = "/var/log" のように = の前後にスペースを入れると、シェルは TARGET_DIR というコマンドを実行しようとしてエラーになります。スペースは入れないよう注意してください。

2. 特殊変数と位置引数(引数の受け取り)

スクリプト実行時に外部から渡された引数は、位置引数(Positional Arguments)として参照できます。

変数名意味・役割
$0実行されたスクリプト自体の名前(ファイル名)
$1, $2, $3第1引数、第2引数、第3引数...
$#渡された引数の総数
$@渡された全引数のリスト("$@" で個別にクォート保持)
$?直前に実行されたコマンドの**終了ステータス**(0は成功、非0は失敗)
$$現在のシェルスクリプトのプロセスID(PID)

位置引数の活用サンプル:

#!/usr/bin/env bash

echo "実行スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "引数の総数: $#"

# 直前コマンドの成功確認
ls "$1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "ディレクトリ $1 は存在します。"
fi

3. クォーテーション(引用符)とコマンド置換

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

単にコマンドを並べるだけでなく、変数や引数を活用することで動的で柔軟なスクリプトが書けるようになります。

1. 変数の定義と参照

シェルスクリプトでの変数定義は 変数名=値 の形式で行います。

#!/usr/bin/env bash

# 変数の定義(=の左右にスペースを入れてはいけない)
TARGET_DIR="/var/log"
SERVER_NAME="web-01"

# 変数の参照($を付ける。${}で囲むと境界が明確になる)
echo "バックアップ対象: ${TARGET_DIR}"
echo "対象サーバー: $SERVER_NAME"

注意: TARGET_DIR = "/var/log" のように = の前後にスペースを入れると、シェルは TARGET_DIR というコマンドを実行しようとしてエラーになります。スペースは入れないよう注意してください。

2. 特殊変数と位置引数(引数の受け取り)

スクリプト実行時に外部から渡された引数は、位置引数(Positional Arguments)として参照できます。

変数名意味・役割
$0実行されたスクリプト自体の名前(ファイル名)
$1, $2, $3第1引数、第2引数、第3引数...
$#渡された引数の総数
$@渡された全引数のリスト("$@" で個別にクォート保持)
$?直前に実行されたコマンドの**終了ステータス**(0は成功、非0は失敗)
$$現在のシェルスクリプトのプロセスID(PID)

位置引数の活用サンプル:

#!/usr/bin/env bash

echo "実行スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "引数の総数: $#"

# 直前コマンドの成功確認
ls "$1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "ディレクトリ $1 は存在します。"
fi

3. クォーテーション(引用符)とコマンド置換

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

パーミッションの仕組みやエラーの解決方法についてはPermission deniedの原因と直し方で詳しく解説しています。

ステップ4:スクリプトの実行(`./` の指定)

実行権限を付与したら、カレントディレクトリを示す ./ を頭に付けてスクリプトを実行します。

./hello.sh

実行結果:

Hello, Shell Script!
2026年 8月 11日 火曜日 17:00:00 JST

※ 単に hello.sh とだけ打つと、セキュリティ上の理由からカレントディレクトリが環境変数 $PATH に含まれていないため「command not found」となります。明示的に ./hello.sh とパスを指定しましょう。

シェルスクリプトの基本文法(変数・引数・クォート)

単にコマンドを並べるだけでなく、変数や引数を活用することで動的で柔軟なスクリプトが書けるようになります。

1. 変数の定義と参照

シェルスクリプトでの変数定義は 変数名=値 の形式で行います。

#!/usr/bin/env bash

# 変数の定義(=の左右にスペースを入れてはいけない)
TARGET_DIR="/var/log"
SERVER_NAME="web-01"

# 変数の参照($を付ける。${}で囲むと境界が明確になる)
echo "バックアップ対象: ${TARGET_DIR}"
echo "対象サーバー: $SERVER_NAME"

注意: TARGET_DIR = "/var/log" のように = の前後にスペースを入れると、シェルは TARGET_DIR というコマンドを実行しようとしてエラーになります。スペースは入れないよう注意してください。

2. 特殊変数と位置引数(引数の受け取り)

スクリプト実行時に外部から渡された引数は、位置引数(Positional Arguments)として参照できます。

変数名意味・役割
$0実行されたスクリプト自体の名前(ファイル名)
$1, $2, $3第1引数、第2引数、第3引数...
$#渡された引数の総数
$@渡された全引数のリスト("$@" で個別にクォート保持)
$?直前に実行されたコマンドの**終了ステータス**(0は成功、非0は失敗)
$$現在のシェルスクリプトのプロセスID(PID)

位置引数の活用サンプル:

#!/usr/bin/env bash

echo "実行スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "引数の総数: $#"

# 直前コマンドの成功確認
ls "$1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "ディレクトリ $1 は存在します。"
fi

3. クォーテーション(引用符)とコマンド置換

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

シェルスクリプトとは、LinuxやUnix系OSにおいて、ターミナルで実行するコマンドをテキストファイルに書き並べ、一括して自動実行できるようにした仕組み(指示書)です。

「毎日決まった時刻にファイルをバックアップする」「複数のログファイルを検索して集計する」「サーバーの環境構築手順を自動化する」といった定型作業を、手動でコマンドを1行ずつ打ち込むことなく、1回の実行で正確かつ高速に処理できます。

この記事では、シェルスクリプトの概要やメリットから、作成・実行の基本4ステップ(シバン `#!/bin/bash` や `chmod +x`)、変数・制御構文(if/for/while)の使い方、すぐに使える実用サンプルコード、バグを防ぐベストプラクティスまで徹底解説します。

シェルスクリプトとは?(役割とメリット)

シェルスクリプトは、日々のLinux操作やサーバー運用を劇的に効率化するための基本ツールです。まずはその定義とメリットを整理しておきましょう。

「シェル」と「シェルスクリプト」の違い

「シェル」と「シェルスクリプト」は混同されやすい言葉ですが、役割が明確に異なります。

用語役割・意味たとえ
シェル(Shell)ユーザーの入力を受け取り、OS(カーネル)に伝えるプログラム(Bash、zsh、shなど)コマンドを翻訳する「通訳者」
シェルスクリプト(Shell Script)シェルに実行させたい複数のコマンドを記述したテキストファイル(`.sh`)通訳者に渡す「進行台本・指示書」

ターミナル上で1行ずつコマンドを打ち込んで対話的に操作する相手がシェルであり、その操作手順をあらかじめファイルに保存して自動化したものがシェルスクリプトです。Bashの詳細についてはBashとは?意味と使い方の記事も参考にしてください。

シェルスクリプトを導入する3つの大きなメリット

  1. 手作業によるタイプミス・手順漏れを防げる
    複雑なコマンド群を毎回手入力すると、打ち間違いや実行順序のミスが発生しやすくなります。スクリプト化しておけば、いつでも同じ正確さで処理を実行できます。
  2. 定型業務・運用作業を高速化&自動化できる
    ログの整理やデータの抽出、バックアップ作業などを数秒で完了できます。さらにcron(タスクスケジュール機能)と組み合わせれば、夜間や定期実行の完全自動化が可能です。
  3. 特別な開発環境・コンパイルが不要
    LinuxやmacOSなどのUnix系環境であれば、テキストエディタと標準のシェル(Bash等)だけで作成・実行できます。C言語やJavaのようなコンパイル作業は一切不要です。

シェルスクリプトの作成から実行までの4ステップ

シェルスクリプトを作成して実行する流れは、次の4ステップに集約されます。

ステップ1:テキストファイルの作成(拡張子は `.sh`)

まずはテキストエディタ(`vim`、`nano`、VS Codeなど)を使ってスクリプトファイルを作成します。拡張子は慣例として .sh を付けます。

nano hello.sh

ステップ2:シバン(Shebang)とコマンドの記述

ファイルの1行目には必ずシバン(Shebang)と呼ばれる特殊な記述を行います。シバンは「このスクリプトをどのインタプリタ(シェル)で実行するか」を指定する宣言です。

#!/usr/bin/env bash

# これはコメントです(画面にメッセージを出力)
echo "Hello, Shell Script!"
date

#!/bin/bash と書くこともできますが、環境によってBashの配置パスが異なる場合に対応できるよう、ポータビリティの高い #!/usr/bin/env bash の記述をおすすめします。

ステップ3:実行権限の付与(`chmod +x`)

作成直後のテキストファイルには「実行権限(execute)」が付与されていません。そのまま実行しようとすると Permission denied エラーが発生するため、chmod コマンドで実行権限を追加します。

chmod +x hello.sh

パーミッションの仕組みやエラーの解決方法についてはPermission deniedの原因と直し方で詳しく解説しています。

ステップ4:スクリプトの実行(`./` の指定)

実行権限を付与したら、カレントディレクトリを示す ./ を頭に付けてスクリプトを実行します。

./hello.sh

実行結果:

Hello, Shell Script!
2026年 8月 11日 火曜日 17:00:00 JST

※ 単に hello.sh とだけ打つと、セキュリティ上の理由からカレントディレクトリが環境変数 $PATH に含まれていないため「command not found」となります。明示的に ./hello.sh とパスを指定しましょう。

シェルスクリプトの基本文法(変数・引数・クォート)

単にコマンドを並べるだけでなく、変数や引数を活用することで動的で柔軟なスクリプトが書けるようになります。

1. 変数の定義と参照

シェルスクリプトでの変数定義は 変数名=値 の形式で行います。

#!/usr/bin/env bash

# 変数の定義(=の左右にスペースを入れてはいけない)
TARGET_DIR="/var/log"
SERVER_NAME="web-01"

# 変数の参照($を付ける。${}で囲むと境界が明確になる)
echo "バックアップ対象: ${TARGET_DIR}"
echo "対象サーバー: $SERVER_NAME"

注意: TARGET_DIR = "/var/log" のように = の前後にスペースを入れると、シェルは TARGET_DIR というコマンドを実行しようとしてエラーになります。スペースは入れないよう注意してください。

2. 特殊変数と位置引数(引数の受け取り)

スクリプト実行時に外部から渡された引数は、位置引数(Positional Arguments)として参照できます。

変数名意味・役割
$0実行されたスクリプト自体の名前(ファイル名)
$1, $2, $3第1引数、第2引数、第3引数...
$#渡された引数の総数
$@渡された全引数のリスト("$@" で個別にクォート保持)
$?直前に実行されたコマンドの**終了ステータス**(0は成功、非0は失敗)
$$現在のシェルスクリプトのプロセスID(PID)

位置引数の活用サンプル:

#!/usr/bin/env bash

echo "実行スクリプト名: $0"
echo "第1引数: $1"
echo "第2引数: $2"
echo "引数の総数: $#"

# 直前コマンドの成功確認
ls "$1" > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "ディレクトリ $1 は存在します。"
fi

3. クォーテーション(引用符)とコマンド置換

シェルスクリプトにおいて、シングルクォート `''` とダブルクォート `""` には重要な意味の違いがあります。

  • ダブルクォート `""`:変数展開(`$VAR`)やコマンド置換(`$(command)`)を実行する。
  • シングルクォート `''`:内部の文字をすべて単なる文字列として扱う(変数展開しない)。
  • コマンド置換 `$(コマンド)`:コマンドの実行結果を変数に代入する(昔のバッククォート `` `command` `` より可読性が高く推奨)。
NAME="Alice"

echo "Hello, $NAME"   # 出力: Hello, Alice (変数展開される)
echo 'Hello, $NAME'   # 出力: Hello, $NAME (そのまま出力)

# コマンドの実行結果を変数に代入(コマンド置換)
TODAY=$(date +%Y-%m-%d)
echo "本日の日付: $TODAY"

制御構文(条件分岐 `if`/`case` と繰り返し `for`/`while`)

条件に応じて処理を変えたり、複数のファイルに対して同じ処理を繰り返すための制御文です。

1. 条件分岐:`if` 文

ファイルが存在するか、数値が一致するかなどの条件判定には if 文を使用します。Bashでは拡張テストブラケット [[ ]] を使うのが一般的です。

#!/usr/bin/env bash

FILE_PATH="./config.conf"

# ファイルが存在するかテスト(-f オプション)
if [[ -f "$FILE_PATH" ]]; then
  echo "設定ファイルが見つかりました: $FILE_PATH"
elif [[ -d "./config" ]]; then
  echo "設定ディレクトリが存在します。"
else
  echo "設定ファイルが存在しません。"
fi

よく使う評価演算子:

分類演算子意味
ファイル比較-f file / -d dir / -e pathファイルが存在 / ディレクトリが存在 / パスが存在
数値比較-eq / -ne / -gt / -lt等しい / 等しくない / より大きい / より小さい
文字列比較== / != / -z str / -n str一致 / 不一致 / 空文字列である / 空でない

2. 条件分岐:`case` 文(多岐分岐)

引数の文字列パターンによって処理を分ける場合、`case` 文を使用するとすっきりと記述できます。

case "$1" in
  start)
    echo "サービスを起動します..."
    ;;
  stop)
    echo "サービスを停止します..."
    ;;
  restart)
    echo "サービスを再起動します..."
    ;;
  *)
    echo "使用方法: $0 {start|stop|restart}"
    exit 1
    ;;
esac

3. 繰り返し処理:`for` 文

リストやワイルドカードで指定したファイル群に対してループ処理を行います。

#!/usr/bin/env bash

# 配列やリストの要素を順に処理
for server in web01 web02 db01; do
  echo "pingチェック: $server"
done

# カレントディレクトリ内の .txt ファイルを順に処理
for file in *.txt; do
  # ファイルが存在しない場合のチェック
  [[ -e "$file" ]] || break
  echo "処理対象ファイル: $file"
done

4. 繰り返し処理:`while` 文(ファイルの1行読み込み)

条件が真の間ループを繰り返します。テキストファイルやコマンド出力を1行ずつ読み込んで処理する際に定番となる構文です。

#!/usr/bin/env bash

# list.txt から1行ずつ読み込んで処理
while IFS= read -r line; do
  echo "行内容: $line"
done < list.txt

IFS=-r オプションを付与することで、行頭・行末の空白保持やバックスラッシュのエスケープ無効化を行い、安全にテキストを読み込めます。詳細はreadコマンドの使い方を参照してください。

実務で役立つ!実践サンプルコード3選

実務でそのまま使える、実用的なシェルスクリプトのサンプルコードを紹介します。

サンプル1:ログファイルの自動バックアップ&圧縮スクリプト

指定したディレクトリ内のログファイルを日付入りアーカイブ(`.tar.gz`)として固めて保存するスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/app"
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_log_${DATE}.tar.gz"

# バックアップ先ディレクトリが存在しなければ作成
mkdir -p "${BACKUP_DIR}"

# ログアーカイブを作成
if tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${LOG_DIR}" .; then
  echo "[SUCCESS] バックアップ完了: ${BACKUP_DIR}/${ARCHIVE_NAME}"
else
  echo "[ERROR] バックアップ作成に失敗しました" >&2
  exit 1
fi

サンプル2:ファイルの一括リネーム(拡張子変更)

ディレクトリ内のすべての .htm ファイルを .html に一括変更する安全なスクリプトです。

#!/usr/bin/env bash
set -euo pipefail

TARGET_DIR="${1:-.}"

for file in "${TARGET_DIR}"/*.htm; do
  # 対象ファイルが存在しない場合を考慮
  [[ -f "$file" ]] || continue
  
  # 新しいファイル名を定義(.htm を .html に置換)
  new_name="${file%.htm}.html"
  
  echo "リネーム: ${file} -> ${new_name}"
  mv "$file" "$new_name"
done

echo "一括リネームが終了しました。"

サンプル3:引数チェック&エラー処理付きの安全スクリプト

必須引数が渡されているかを検証し、正しくない場合に使い方(Usage)を表示して終了する堅牢な実装パターンです。

#!/usr/bin/env bash
set -euo pipefail

# ヘルプ・使い方を表示する関数
usage() {
  echo "使用方法: $0 <対象ディレクトリ> <出力ファイル名>"
  echo "例: $0 /var/www/html site_backup.tar.gz"
  exit 1
}

# 引数の個数をチェック(2つ未満ならヘルプを表示)
if [[ $# -lt 2 ]]; then
  usage
fi

SRC_DIR="$1"
OUTPUT_FILE="$2"

# 対象ディレクトリの存在チェック
if [[ ! -d "$SRC_DIR" ]]; then
  echo "エラー: ディレクトリ '$SRC_DIR' が存在しません。" >&2
  exit 1
fi

echo "処理を開始します: $SRC_DIR -> $OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" "$SRC_DIR"
echo "正常に完了しました。"

バグを防ぐ!安全なシェルスクリプト作成のベストプラクティス

シェルスクリプトは柔軟な反面、意図しない挙動や誤消去などの事故を起こしやすい面もあります。安全に運用するための3つの鉄則を押さえましょう。

1. 冒頭に `set -euo pipefail` を記述する(厳格モード)

デフォルトのシェルスクリプトは、途中のコマンドがエラーを起こしても処理を中断せず最後まで実行を続けてしまいます。スクリプトの冒頭に以下を設定することで、予期せぬ事故を防げます。

set -euo pipefail
オプション効果
set -eコマンドが1つでも失敗(終了ステータス非0)したら即座にスクリプトを終了する
set -u未定義の変数を使用しようとした際にエラーを発生させて終了する
set -o pipefailパイプライン(|)内のどこかでエラーが発生した場合に、その失敗を全体のエラーとして扱う

2. 変数は常にダブルクォートで囲む(`"$VAR"`)

パス名やファイル名にスペース(空白文字)が含まれている場合、クォートで囲んでいないと複数の引数として分割されてしまい、誤動作の原因になります。

# 危険な書き方(スペースが含まれると壊れる)
rm -rf $DIR/$FILE

# 安全な書き方(常にダブルクォートで保護)
rm -rf "${DIR}/${FILE}"

3. 事前文法チェック(`bash -n`)と ShellCheck の活用

スクリプトを実行する前に、構文エラーがないかチェックできます。

# bash の文法チェック(実行せずに構文のみ確認)
bash -n script.sh

# 静的解析ツール ShellCheck の活用
shellcheck script.sh

よくあるトラブルとFAQ

Q1. `Permission denied` と表示されて実行できない

ファイルに実行権限が付与されていません。chmod +x スクリプト名.sh を実行して実行権限を付与してください。

Q2. `\r: command not found` や `syntax error near unexpected token` と出る

Windows環境で作成・編集したテキストファイルの改行コードが CRLF になっていることが原因です。Linuxの改行コードである LF に変換してください。dos2unix コマンドやVS Codeの右下ステータスバーから改行コードを「LF」に変更して保存し直すことで解決します。

Q3. `sh script.sh` と `./script.sh` は何が違う?

sh script.sh は、シバン(1行目の #!/bin/bash 等)を無視して /bin/sh インタプリタで強制実行します。一方 ./script.sh は、ファイル自体の実行権限を確認し、シバンで指定されたシェルで実行します。Bash拡張機能(`[[ ]]` や配列など)を使っている場合は ./script.sh または bash script.sh で実行してください。

まとめ

シェルスクリプトは、Linuxコマンドを保存して自動化するためのシンプルかつ非常に強力なツールです。

  • 1行目にシバン #!/usr/bin/env bash を書く
  • chmod +x script.sh で実行権限を付与する
  • 変数・クォート・条件分岐(`if`)・繰り返し(`for`/`while`)を活用する
  • 事故防止のため set -euo pipefail をスクリプト冒頭に記述する

まずは数行の簡単なコマンドを並べたスクリプトの作成から始め、日々の手動作業を1つずつ自動化してみましょう!

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント