コマンドライン基礎 - シェル・bash・コマンド実行の仕組み

コマンドライン基礎 - シェル・bash・コマンド実行の仕組み

この記事で達成できること

  • シェルとは何か、bash がコマンドを解釈・実行する流れを説明できる
  • type / which でコマンドの種別と実体を正確に判別できる
  • PATH の解決順序を理解し「command not found」の原因を特定できる
  • 引用符(シングル / ダブル / バックスラッシュ)の挙動の違いを使い分けられる
  • コマンド履歴とヒストリ展開を実務で活用できる

LPIC-1 主題 103.1「コマンドラインで操作する」の中核。シェルの動作モデルを正確に把握することが、以降のテキスト処理・プロセス管理すべての土台になる。

シェルとコマンド実行の判断フロー

シェルはユーザーが入力した行を解釈し、コマンドを起動するプログラム。bash(Bourne-Again Shell)が多くのディストリビューションの既定。コマンドを入力したとき、bash はまずコマンドライン解釈段階でエイリアス(alias で確認、例 llls -l)を展開する。エイリアスは検索順序の構成要素ではなく、検索より前の別段階で先に置換される。展開後の語に対して、bash は以下の順序で実体を解決する。

順序 種別 確認コマンド
1 シェル関数 declare -F ユーザー定義関数
2 シェル組込みコマンド type -a cmd cd / echo / pwd
3 PATH 上の外部コマンド which cmd /bin/ls

この順序を把握していないと「echo は組込みなのか /bin/echo なのか」「time が動作しない」といった現象を説明できない。

手順

Step 1: シェルの種別と版を確認

echo $SHELL
bash --version
/bin/bash
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

$SHELL はログインシェル、現在対話実行中のシェルは $0 または ps -p $$ で確認する。

Step 2: コマンドの種別を判定する

type cd
type ls
type -a echo
cd is a shell builtin
ls is aliased to `ls --color=auto'
echo is a shell builtin
echo is /usr/bin/echo

type は bash 組込みで、解決順序そのものを反映する。-a を付けると同名のすべての候補を表示する。外部コマンドのパスだけが欲しい場合は which を使う。

which cp
/usr/bin/cp

whichPATH 上の最初の一致のみを返す。組込みやエイリアスは検出しないため、種別判定には type が優先される。

Step 3: PATH の解決順序を理解する

echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

PATH はコロン区切りのディレクトリ一覧。bash は外部コマンドを左から順に検索し、最初に見つかった実行ファイルを起動する。同名コマンドが複数ディレクトリに存在する場合、PATH の先頭にある方が優先される。

Step 4: 引用符でメタ文字を制御する

name=world
echo "hello $name"
echo 'hello $name'
echo hello \$name
hello world
hello $name
hello $name

ダブルクオート(")は変数展開・コマンド置換を行うがワード分割とグロブを抑止する。シングルクオート(')はすべての展開を抑止しリテラルとして扱う。バックスラッシュ(\)は直後の 1 文字をエスケープする。

Step 5: コマンド履歴を活用する

history 5
!!
!123
!grep
  120  cd /var/log
  121  ls -l
  122  grep error syslog
  123  tail -f syslog
  124  history 5

!! は直前のコマンド、!n は履歴番号 n、!string は string で始まる最新コマンドを再実行するヒストリ展開。Ctrl+r で履歴のインクリメンタル検索もできる。

なぜこの順序か

bash のコマンド検索順序は厳密には「関数 → 組込み → 外部(PATH)」で、エイリアスはこの検索順序の一部ではなくコマンドライン解釈段階(検索より前)で先に展開される。ユーザー定義やシェル内部処理を外部コマンドより優先するための設計である。例えば echo は組込みと /usr/bin/echo の両方が存在するが、組込みが優先されることでサブプロセス起動のコストを避けている。time が「コマンドではない」と振る舞うのも、time がパイプライン全体を計測する bash の予約語(キーワード)であり、組込みコマンドより前段で解釈されるため。

PATH の前方優先は、/usr/local/bin に置いた独自ビルドのコマンドをシステム標準より優先させる運用を可能にする。逆に意図せぬ同名コマンドが先に解決されると事故になるため、種別不明時は必ず type -a で全候補を確認する。

トラブルシューティング

症状: command not found が出る

原因: コマンドが PATH 上に存在しない、または PATH 自体が壊れている

確認:

echo $PATH
type -a cmdname

対処: 実行ファイルの所在を find / -name cmdname -type f 2>/dev/null で特定し、そのディレクトリを PATH に追加する。PATH が空に近い場合は .bashrc / .bash_profile の設定ミスを疑う。

症状: 変数が展開されない

原因: シングルクオートで囲っている

確認:

echo '$HOME'
echo "$HOME"

対処: 変数展開が必要な箇所はダブルクオートを使う。リテラルとして $ を出したい場合のみシングルクオートまたは \$ を使う。

症状: which と type で結果が食い違う

原因: which は外部コマンドのみ、type はエイリアス・組込みも含めて解決順を反映するため

確認:

type -a ls
which ls

対処: コマンドが実際にどう実行されるかを知りたい場合は常に type を信頼する。which はスクリプト内で実行ファイルパスを取得する用途に限定する。

作業完了チェックリスト

  • [ ] echo $SHELLbash --version でシェル環境を確認した
  • [ ] type -a で主要コマンドの種別を確認した
  • [ ] echo $PATH で検索パスの順序を把握した
  • [ ] シングル / ダブルクオートの展開差を実機で確認した
  • [ ] history とヒストリ展開(!! / !n)を試した

まとめ

場面 コマンド 目的
種別判定 type -a cmd エイリアス/関数/組込み/外部を判別
実体パス which cmd PATH 上の実行ファイルパス取得
パス確認 echo $PATH コマンド検索順序の把握
履歴再実行 !! / !n 直前/番号指定のコマンド再実行
展開抑止 '...' / \ メタ文字をリテラル化

シェルの解決順序と引用符の挙動は、LPIC-1 全体を通じて前提となる基礎。次は変数を永続化するシェル環境設定に進むと理解が連結する。

次に読む