ターミナルの黒い画面に文字を打ち込んで Enter を押すと、そこで何が起きているのか。
カーネル、シェル、プロセスという言葉を、順番に、一つずつ。
「接触面」という言葉から入るのが近道です。
interface は inter(間)+ face(面)で、接触面を意味します。異なる二つのものが触れ合う境目のことです。
ユーザーインターフェース(UI)とは、人間と機械が触れ合う面のこと。その面が何でできているかで名前が変わります。
| 略語 | 正式名称 | 面の材質 |
|---|---|---|
| GUI | Graphical User Interface | 図形(アイコン・ボタン・窓) |
| CLI | Command Line Interface | 文字(打ち込むコマンド) |
読み方は「グイ」または「ジーユーアイ」、「シーエルアイ」です。
アイコンをクリックする、ウィンドウをドラッグする、ボタンを押す。マウスやタッチで、画面に見えているものを直接指し示す方式です。Finder、エクスプローラー、スマートフォンのホーム画面 ─ 日常的に触れているものはほぼすべて GUI です。
文字を1行打ち込んで Enter を押す。この資料で扱っている黒い画面がこれです。
重要なのは、GUI も CLI も、やっていることは同じだという点です。どちらも OS への窓口であって、最終的にカーネルへ同じ依頼を出しています。
人間の記憶には二種類あります。再認(見せられれば「あ、これだ」と分かる)と、想起(何も見ずに自分で思い出す)です。
GUI は再認に頼る設計です。メニューを開けば選択肢が並んでいるので、覚えていなくても探せます。CLI は想起に頼る設計です。mv という名前を知らなければ、そのコマンドは存在しないのと同じです。
この違いが、そのまま得手不得手になります。
| GUI | CLI | |
|---|---|---|
| 初めての人 | 易しい | 難しい |
| 慣れた人 | 遅い | 速い |
| 知らない機能を見つける | 得意 | 苦手 |
| 同じ作業を100回 | 苦手 | 得意 |
| 手順を人に渡す | 画面録画や手順書が必要 | 文字列をそのまま送れる |
| 遠隔のサーバー操作 | 重い | 軽い |
ファイル100個の名前を一括で変えるとします。GUI なら100回クリックして100回タイプする。30分かかり、来月また同じことをします。CLI なら1行です。1秒で終わり、しかもその1行を保存しておけば来月もそのまま使えます。
CLI が速いのはタイプが速いからではありません。手順そのものを文字として保存・再利用・送信できるからです。マウスの動きは保存できません。
文字だけで GUI のような画面を描く方式を TUI(Text User Interface)と呼びます。文字で枠線を引き、カーソルキーで項目を選ぶ。Claude Code がまさにこれで、CLI と GUI の中間にあたります。
もう一つ、API(Application Programming Interface)があります。接触面の両側がプログラムとプログラムである場合の呼び名です。
| 種類 | 接触面の両側 |
|---|---|
| GUI・CLI・TUI | 人間 ↔ 機械 |
| API | 機械 ↔ 機械 |
業務システムの画面を人が操作するのが GUI、そこへプログラムがアクセスするのが API という関係になります。
どちらか一方を選ぶものではありません。VS Code は GUI の中にターミナルが埋め込まれていますし、GitHub も Vercel も同じ操作を Web 画面とコマンドの両方で提供しています。探すとき・眺めるときは GUI、繰り返すとき・人に渡すときは CLI。これが実務的な落としどころです。
名前がそのまま答えになっています。
shell は英語で「殻」です。何の殻かというと、OS の中心部を包む殻です。
その中心部は カーネル(kernel)と呼ばれます。kernel は「核」「木の実の中身」という意味の単語です。つまり OS を木の実に見立てて、食べる部分=カーネル、それを包む殻=シェル、と名付けられています。比喩というより、そのままの命名です。
カーネルは、メモリの割り当て、ディスクへの読み書き、CPU の配分といった実務を担当しています。ただしカーネルは日本語も英語も理解しません。決められた形式でプログラムから呼び出されること(システムコール)しか受け付けません。
人間はその形式で入力できません。だから間に「人間の言葉を受け取って、カーネルへの依頼に翻訳する」層が必要になる。それがシェルです。
ここが一番の勘所かもしれません。Windows のエクスプローラーや Mac の Finder も、役割としてはシェルです。実際 Microsoft は explorer.exe を公式に「Windows シェル」と呼んでいます。
フォルダのアイコンをダブルクリックする。cd project と打つ。どちらも「そのフォルダを開け」とカーネルに依頼しているという点で同じです。窓口の形が「マウスで触る」か「文字を打つ」かの違いにすぎません。
| 種類 | 具体例 |
|---|---|
| GUI シェル | エクスプローラー、Finder |
| CLI シェル | bash、zsh、PowerShell、cmd.exe |
ですので「シェル=黒い画面」ではありません。シェル=OS への窓口であって、黒い画面はその一形態です。
待つ(プロンプトを出して入力を待つ)。解釈する(打たれた文字列を切り分ける)。依頼する(該当のプログラムを探して動かすようカーネルに頼む)。表示する。そしてまた最初に戻る。延々とこの繰り返しです。
ls は bash の機能ではありません。/bin/ls という独立したプログラムファイルです。bash はそれを探して起動しているだけで、一覧表示の処理自体は何もしていません。
だから「探しに行く場所のリスト」が必要になります。それが PATH です。ここがつながると、command not found というエラーが「そんなコマンドは存在しない」ではなく「リストに載っている場所を全部見たけれど、その名前のファイルが無かった」という意味だと分かります。
多くの人がここで混乱します。
ターミナル(端末エミュレータ)は、文字を表示しキー入力を受け取る「窓」です。Windows Terminal、Mac の Terminal.app がこれにあたります。
シェルは、打ち込まれた文字列を解釈して実際に実行する「頭脳」です。bash、zsh、PowerShell、cmd.exe がこれにあたります。
窓を替えても中身のシェルは同じ、逆に同じ窓の中でシェルだけ切り替える、ということが起こります。
「シェル」が分類名で、bash はその中の具体的な1つ。ブラウザと Chrome の関係です。
bash は Bourne Again SHell の略で、読みは「バッシュ」です。
1979年に Stephen Bourne という人が作った sh(Bourne シェル)が Unix の標準でした。1989年にそれを一から作り直したのが bash です。"Bourne Again" は "born again"(生まれ変わった)との駄洒落になっています。つまり bash は、40年以上使われてきたシェルの現在の主流版です。
Linux サーバーはほぼ必ず bash です。Mac は 2019年以降 zsh が標準ですが、基本操作は bash と同じです。Windows には標準では入っておらず、Git をインストールすると付いてくる Git Bash か、WSL を導入すると使えるようになります。
ここが最初につまずくところです。ネットの記事にこう書いてあったとします。
この先頭の $ は打つ文字ではありません。「入力を待っています」という合図の記号です。実際に打つのは npm install の部分だけ。$ npm install をまるごとコピーして貼り付けるとエラーになります。
実際の画面はこう見えています。
| 部分 | 意味 |
|---|---|
hokama | ログインしているユーザー名 |
MacBook | この機械の名前 |
~/project | 今いるフォルダ(~ はホーム) |
$ | プロンプト記号。ここから右が自分の入力 |
ls | 実際に打ったコマンド |
この $ より左の部分をまとめてプロンプトと呼びます。設定で見た目が変わるので、人によって表示は違います。
この5つだけで「フォルダの中を歩き回って中身を確認する」ができます。GUI でいうエクスプローラーの操作に相当します。
ここまでの話が全部つながる箇所です。ls -l *.txt と打った場合を追います。
キーを1つ押すたびに、その文字がシェルへ送られ、同時に画面へ返って表示されます。これをエコーと呼びます。バックスペースや矢印キーで打ち間違いを直せるのも、この段階でシェルが編集機能を提供しているからです。
改行文字が送られます。シェルはこれを見て「1行の入力が確定した」と判断し、受付を終えて処理に入ります。
受け取った文字列を、意味のある単位に分解します。ls がコマンド名、-l と *.txt が引数、という具合です。
*.txt を、実際に存在するファイル名の並びに置き換えます。~ はホームのパスに、$HOME のような変数はその値に置き換わります。
ワイルドカード * を展開しているのは ls ではなくシェルです。ls は展開が済んだ後のファイル名リストを受け取るだけで、* という記号を見ることすらありません。
まず自分が内蔵している機能(ビルトイン)かどうかを確認します。違えばエイリアス(別名)かを確認。それも違えば、PATH に並んだフォルダを先頭から順に見て ls という名前のファイルを探します。/usr/bin/ls を発見。見つからなければ、ここで command not found が出て終わります。
ここが最も独特な部分です。bash はまず自分自身のコピーを作ります(fork)。次に、そのコピーの中身を /usr/bin/ls のプログラムで丸ごと上書きします(exec)。この瞬間、bash の複製だったものが ls になります。
親である bash は、その横で子の終了をただ待ちます。
ls がカーネルに「このフォルダの中身を教えてほしい」と依頼します(システムコール)。カーネルがディスクを読み、結果を返します。ls はそれを整形して標準出力へ書き出します。
標準出力の先はターミナルにつながっています。ターミナルは届いた文字をフォントで描画し、ここで初めて人間の目に見えます。
ls は終了コード(成功なら 0)を残して消えます。bash は待機から復帰してその値を $? に保存し、新しいプロンプトを表示して 1 に戻ります。
ここまで読むと、ある疑問が解けます。なぜ cd は独立したプログラムではなく、bash が内蔵しているのか。
もし cd が /bin/cd という独立したプログラムだったとします。すると上の図のとおり、bash は分身を作り、その分身が cd になってフォルダを移動します。しかし移動したのは分身であって、親の bash ではありません。分身が仕事を終えて消えた瞬間、何事もなかったように元の場所へ戻ってしまいます。
だから cd は bash 自身が実行しなければならない。「自分の居場所を変えられるのは自分だけ」という、ごく当たり前の制約から来ています。
1970年代は画面に文字しか出せなかったので必然でした。今も残っているのは、文字にしかない性質があるからです。記録できる(打った内容を保存すればそのまま再実行できる)。渡せる(手順を文字列で人に送れる。マウスの動きは送れない)。連結できる(| でコマンド同士をつなげられる)。
マウス操作は速いけれど、100回繰り返すことも、人に正確に渡すこともできません。Claude Code が文字でやりとりしているのも同じ理由です。
ここまでの挙動は、すべて数個の原則から導かれています。
Unix は1969年、ベル研究所の片隅で始まりました。Ken Thompson が、使われなくなった小型機を借りて、会社の正式なプロジェクトでもなく作り始めたものです。メモリは数キロバイト。大きなプログラムは物理的に入りませんでした。
この制約が、そのまま設計思想になりました。そして半世紀後、制約がとうに消えた今も、思想のほうが残っています。残ったのは、それが単なる妥協ではなく正しかったからです。
ファイル、フォルダ、キーボード、画面、プリンタ、ネットワーク接続。Unix ではこれらがすべて「開く・読む・書く・閉じる」という同じ4つの操作で扱えます。
だから > でファイルへ送るのも画面へ送るのも同じ構文になります。/dev/null という「書き込むと消える偽ファイル」が捨て場として機能します。標準入力・標準出力・標準エラー出力は、実体としては 0番・1番・2番というただのファイル番号です。
効果は、覚えることが激減することです。新しい種類の装置が登場しても、既存の知識でそのまま扱えます。
ls は一覧するだけです。並べ替えも検索も集計もしません。sort は並べ替えるだけ、grep は探すだけ。
だから ls は * を展開しません。それはシェルの仕事だからです。役割が重ならないよう、徹底して分けられています。
効果は、各プログラムが小さく保たれ、正しさを確認しやすくなることです。一つ直しても他が壊れません。
原則1と2が揃うと、掛け算になります。100個の小さな道具は、100通りではなく組み合わせの数だけの使い道を持ちます。| はその接続端子です。
大きな一枚岩を作るのではなく、小さな部品を作って、必要なときに毎回組み立てる。これが Unix の中心的な発想です。
すべてのプログラムが同じ言語 ─ つまり文字 ─ を話せば、どれとどれでも接続できます。もし各プログラムが独自形式を使えば、N個のプログラムをつなぐのに N² 個の変換器が必要になります。
副次的な効果として、人間が中身を読めます。だから Unix では設定ファイルもログもテキストです。JSON、YAML、Markdown、そして Claude Code に渡す指示書も、すべてこの思想の延長線上にあります。
成功したコマンドは何も言いません。cp a.txt b.txt が成功すると、画面は無反応のままです。
初学者が最も戸惑う挙動ですが、理由があります。出力はパイプで次のコマンドへ流すためのものだからです。もし「コピーしました」と表示したら、その一文が次のコマンドへ流れ込んで邪魔になります。
だから、うまくいったかどうかは $? という終了コードで確認します。何も出ないのは、うまくいった証拠です。
設定は読めるテキストファイルに置く。動作は追跡できるようにする。隠された状態を作らない。
これは「直せる」という価値に直結します。GUI の「なぜか動かない」に対して、CLI は「どこで止まったか」が見えます。エラーメッセージが読めるのも、途中経過を確認できるのも、この原則の帰結です。
機械の1秒を節約するより、人間の1時間を節約するほうが価値がある。この判断基準が、多少非効率でも読みやすく書きやすい形を選ばせています。
自動化の本当の正当化もここにあります。速いからではなく、人間が同じことを二度やらなくて済むからです。
原則4(テキストが共通語)には代償があります。テキストは構造を失うということです。
ls -l の出力からファイルサイズを取り出すには「左から5列目」と指定するしかありません。表示形式が少し変わっただけで壊れます。日付の書式が変わっただけで動かなくなります。
PowerShell はこの弱点を見て、テキストではなくオブジェクトを流す設計を選びました。得たものは頑健さ、失ったものは他言語のプログラムとの接続性です。どちらが正しいかではなく、何を優先するかの選択だと理解するのが正確です。
これらの原則は、スクリプトや業務ツールを自作するときにそのまま使えます。
| 原則 | 実務への翻訳 |
|---|---|
| 一つのことを | 1つのスクリプトに1つの役割。「集計もメール送信もする」は分ける |
| 組み合わせる | 単体で完結させず、出力を次へ渡せる形にする |
| テキストを共通語に | 出力は CSV か JSON。人が読めて、機械も読める形式を選ぶ |
| 沈黙は成功 | 正常時は静かに。異常時だけ、何がどこで起きたかを出す |
| 透明であること | 設定値をコード内に埋め込まず、外部のテキストファイルに置く |
| 人間の時間が高い | 1回しかやらない作業は自動化しない。3回目からが分岐点 |
Claude Code はこの系譜の直系にあります。小さな道具(読む・書く・探す・実行する)を組み合わせて動く。指示はテキストで渡す。状態は隠さずファイルに置く。
1969年に数キロバイトのメモリの中で生まれた作法が、そのまま現在の道具の作法になっているということです。
bash と PowerShell の決定的な違いは、コマンドの間を流れるものの正体です。
bash や cmd はコマンド間でテキストを受け渡します。PowerShell は .NET のオブジェクトを受け渡します。
たとえば CPU を多く使っているプロセスを上位5件出す場合。
$_ は「パイプで流れてきた今の1件」を指します。文字列を切り出しているのではなく、CPU というプロパティを直接見ているのがポイントです。
コマンドレットの名前は必ず動詞-名詞の形をとります(Get- Set- New- Remove- Start- Stop- Test- Export-)。この規則を知っているだけで、知らないコマンドの意味が推測できます。
PowerShell はこの3つを覚えれば独力で進められます。
とくに Get-Member が要です。パイプの左から何が流れてきているのか、どんなプロパティを持っているのかが見えるので、「オブジェクトが流れる」という感覚が身体に入ります。bash なら man コマンド名、cmd なら コマンド /? が同じ役割です。
これだけ押さえておけば、たいていの技術記事は読めます。
$ や % や > で終わる行。この記号自体は打たない。/Users/hokama/project のような絶対パスと、.(今いる場所)..(一つ上)~(ホーム)を使う相対パスがある。pwd で確認できる。PATH は「実行ファイルを探しに行く場所のリスト」で、コマンドが見つからない原因の大半はこれ。> でファイルに落としてもエラーだけ画面に残る。|> >>> は上書き、>> は追記。ls -l /tmp の -l がオプション、/tmp が引数。オプションは動作を変える指定。$?、PowerShell では $LASTEXITCODE、cmd では %ERRORLEVEL% で確認。cd echo export など。独立したプログラムではない。ls が Get-ChildItem の別名として登録されている。sudo。同じ操作が、環境によってどう呼ばれるか。
| やりたいこと | cmd | PowerShell | bash / zsh |
|---|---|---|---|
| 一覧表示 | dir | Get-ChildItem | ls |
| 移動 | cd | Set-Location | cd |
| 今いる場所 | cd | Get-Location | pwd |
| 中身を見る | type | Get-Content | cat |
| コピー | copy | Copy-Item | cp |
| 移動 / 改名 | move | Move-Item | mv |
| 削除 | del | Remove-Item | rm |
| フォルダ作成 | mkdir | New-Item | mkdir |
| 検索 | findstr | Select-String | grep |
| 画面クリア | cls | Clear-Host | clear |
| 環境変数 | %PATH% | $env:PATH | $PATH |
| 使い方を見る | cmd /? | Get-Help | man |
PowerShell では ls cd cat といった Unix 風の別名がそのまま使えるので、Mac と Windows の行き来はさほど負担になりません。
実際に手を動かすと必ず出会う5つ。
.ps1 を実行しようとするとセキュリティエラーが出ます。既定でスクリプト実行が禁止されているためです。一度だけ以下を実行します。
PATH の変更は、すでに開いているターミナルには反映されません。ターミナルを閉じて開き直すだけで解決することがほとんどです。
PowerShell 5.1 は日本語環境で Shift-JIS 系を既定にします。UTF-8 のファイルが化けたら PowerShell 7 へ移るのが早道です。cmd の場合は chcp 65001 で UTF-8 に切り替わります。
&& が効かないPowerShell 5.1 では使えません。7 以降で使えるようになりました。5.1 なら ; で区切ります。bash では最初から使えます。
ここまでの話は、結局のところ一つのことに集約されます。コマンドを打つとは、シェルに翻訳を頼むことであり、シェル自身はほとんど何もしていない、ということです。
エラーが出たときは「シェルの段階で止まったのか、その先のプログラムで止まったのか」を切り分けると、原因にたどり着くのが速くなります。