シェルとコマンドライン

シェルとは

シェルは、キーボードから打ち込んだコマンド(文字の命令)を解釈してOSに伝えるプログラムです。bash や zsh が代表的で、[[Linux]] やmacOSのターミナル、WindowsのWSLで使います。

ls -la              # ファイル一覧を詳細表示
cd projects/app     # ディレクトリ移動
grep -r "TODO" src/ # src内からTODOを検索

初学者向けポイント

  • GUIより速く、繰り返し・自動化に圧倒的に強いのが価値。同じ操作をスクリプトにして再実行できる
  • コマンド オプション 引数 が基本形。--helpman でその場で調べられる
  • パイプ | で「あるコマンドの出力を次のコマンドの入力へ」つなげるのがUNIX流

最初に覚えるコマンド

コマンド役割
ls / cd / pwdファイル一覧 / 移動 / 現在地
cat / lessファイルの中身を見る
grepテキスト検索
findファイル検索
curlHTTP リクエストを送る

ターミナル・シェル・プロンプトの違い

最初に混乱しやすいのが用語です。3つは役割が違います。

  • ターミナル — 文字を表示してキー入力を受け取る「窓」。macOSのターミナル.app や Windows Terminal
  • シェル — その窓の中で動き、入力を解釈して実行する「中身」。bash・zsh・fish など
  • プロンプト — 入力待ちを示す $% の記号。これはシェルが表示している

同じターミナルのまま、中で動くシェルだけを差し替えられます。ログイン時の既定のシェルは echo $SHELL、いま動いているシェルは ps -p $$ で確認できます($SHELL は既定の設定を指すため、途中で別のシェルを起動しても変わりません)。教材どおりに打ったのに動かないときは、まずシェルの種類の違いを疑います。

パイプとリダイレクトが本体

コマンドを単体で暗記するより、つなぎ方を覚えるほうが効きます。UNIX系のコマンドは、小さな道具を組み合わせて使う前提で設計されているからです。

grep ERROR app.log | wc -l           # ログ中のERROR行を数える
sort access.log | uniq -c | sort -rn # 重複を数えて多い順に並べる
./deploy.sh > deploy.log 2>&1        # 標準出力とエラー出力をまとめて記録
  • |(パイプ)— 左の出力をそのまま右の入力へ渡す
  • > — 出力をファイルへ上書き保存する。追記は >>>> のつもりで > を打ち、既存のログを消す事故が定番
  • 2>&1 — エラー出力(2番)を標準出力(1番)へ合流させる。付け忘れると、いちばん知りたいエラーだけがログに残らない

つまずきポイント

場面何が起きているか
cd Documents/My Project が失敗する空白で引数が2つに割れる。"My Project" と引用符で囲む
"$USER"'$USER' で結果が違うダブルクォートは変数を展開し、シングルクォートは文字のまま扱う
command not foundコマンドを探す先を並べた環境変数 PATH に、そのディレクトリが入っていない
処理が終わらないCtrl+C で中断する。Ctrl+D は入力の終わりで、意味が違う

いちばん怖いのは削除です。rm -rf "$DIR"/*DIR が未設定のままだと rm -rf /* と解釈され、システム全体を消しにいきます。シェルにゴミ箱はなく rm は取り消せないので、まず同じ条件を ls で試して消える対象を目で確かめてから rm に置き換えるのが安全です。

スクリプトにして再利用する

同じ手順を2回打ったら、ファイルに保存してスクリプトにします。

#!/bin/bash
set -euo pipefail   # 失敗したら即中断・未定義変数を検出・パイプ途中の失敗も拾う

cd /opt/app
git pull
npm ci

1行目の #!シバンと呼ばれ、どのシェルで実行するかの指定です。chmod +x deploy.sh で実行権限を付ければ ./deploy.sh と打つだけで動きます([[ファイルシステムとパーミッション]])。set -euo pipefail を先頭に書く習慣は特に重要で、これが無いと途中のコマンドが失敗しても残りが走り続け、「失敗したのに成功したように見える」デプロイになります。

ここから先の地図

シェルは目的ではなく道具なので、「何をしたいか」によって次に読むものが変わります。4つの群に整理します。

リモートのサーバーを操作する

手元のPCではなく、借りたサーバーへログインして作業するのが実務の基本形です。接続の標準が [[SSH]]、ログインした先の世界そのものが [[Linux]]。そこで最初にぶつかる「権限が無くて動かない」を扱うのが [[ファイルシステムとパーミッション]]、必要なソフトの入れ方が [[Linuxパッケージ管理]] です。

動かし続ける・決まった時刻に動かす

コマンドを1回打って終わりではなく、止めずに動かす段階です。常駐サービスの起動と異常時の自動復旧は [[systemdとサービス管理]]、毎晩2時のような定時実行は [[ジョブスケジューリング(cron)]] が担います。どちらも実行される中身はシェルコマンドそのもので、「手で打つと動くのに自動実行だと動かない」という定番の罠もそこで扱います。

調べる・切り分ける

障害対応では「どこまでは正常か」を順に確かめます。繋がらないときの切り分け手順は [[ネットワーク診断コマンド]]。サーバーが1台なら grep でログを追えますが、複数台に分散すると手作業では追いきれなくなり、[[オブザーバビリティ]] の仕組みが要ります。

手作業から自動化へ進める

スクリプトができたら、次はその実行を人手から離します。コミットやプルリクエストをきっかけに自動で走らせるのが [[CI/CD]]、同じ設定を多数のサーバーへ配るのが [[Ansibleと構成管理]] です。分岐やデータ加工が増えてシェルスクリプトが読みづらくなってきたら、[[Python]] のような言語へ移す判断どきです。

関連技術とのつながり

  • [[Linux]] — シェル操作の主戦場
  • [[Git]] — 本来はコマンドラインツール。シェルから使うと理解が深まる
  • [[CI/CD]] — パイプラインの中身はほぼシェルスクリプト
  • [[SSH]] — シェルをリモートのサーバーで開くための標準手段
  • [[ファイルシステムとパーミッション]] — 「動かない」の原因が権限であることは非常に多い
Q: ターミナル・シェル・プロンプトのうち、打ち込んだコマンドを解釈して実行するのはどれ?
- [ ] ターミナル
- [x] シェル
- [ ] プロンプト
解説: ターミナルは文字の表示と入力を受け取る窓、プロンプトは入力待ちを示す記号で、コマンドを解釈するのは中で動くシェル(bash や zsh)です。

Q: コマンドの実行時に `2>&1` を付ける目的はどれ?
- [ ] コマンドを2回繰り返して実行する
- [x] エラー出力を標準出力へ合流させ、まとめて記録できるようにする
- [ ] 出力を上書きではなく追記に切り替える
解説: 2番がエラー出力、1番が標準出力です。`2>&1` を付けないと、いちばん知りたいエラーだけがログに残りません。追記への切り替えは `>>` です。

Q: シェルスクリプトの先頭に `set -euo pipefail` を書かないと起きやすい問題はどれ?
- [ ] スクリプトに実行権限を付けられなくなる
- [ ] シバンの行が無視されて別のシェルで実行される
- [x] 途中のコマンドが失敗しても残りが走り続け、失敗が成功のように見える
解説: 失敗時に即中断させないと、エラーを無視したままスクリプトが最後まで完了してしまいます。実行権限は chmod +x、実行するシェルの指定はシバンの役割です。