0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#0221(2025/08/21)カーネル実行とbash実行の違い

Posted at

カーネル実行とbash実行の違い

要点:./script.sh は「カーネルがファイルを実行」し、bash script.sh は「bash がファイルを読み取って解釈する」。前者は execvex ビット、後者は open/readr ビットが主役。

はじめに(前提と結論)

OS の挙動を正確に掴むには、「誰が exec するのか」「どの権限ビットを見るのか」「shebang(#!)は誰がいつ解釈するのか」を分けて理解するのが近道です。

  • ./script.sh:親シェルが execve("./script.sh") をカーネルに依頼し、カーネルが実行可否を判定します。ファイルに 実行権限(x) が必要。先頭が #! なら カーネルが指定インタプリタ(例:/usr/bin/env bash)を起動して引数にスクリプトを渡します。
  • bash script.sh:親シェルは execve("/bin/bash", ["bash", "script.sh"]) を呼び、bash プロセスが自分でファイルを開いて読み取るだけ。必要なのは 読み取り権限(r)。shebang は コメント扱いで基本的に無視され、bash の言語仕様で解釈されます。

結論として、OS カーネルの実行パスに乗せるか(execve)/ユーザ空間のインタプリタに読み込ませるかが本質です。この違いは、権限、マウントオプション、エラーパターン、セキュリティ制御、ポータビリティに直結します。


技術的な流れの違い(システムコール観点)

1) ./script.sh(直接実行)

  1. 親シェルが fork → 子プロセスが execve("./script.sh", argv, envp) をカーネルに依頼。
  2. カーネルは当該ファイルの x ビット、実効 UID/GID、ACL、マウントフラグ(noexec など)を検査。要件を満たさない場合は EACCES
  3. ファイル先頭が #! の場合、カーネルが shebang を解釈し、指定インタプリタ(+shebang 行に書かれた追加引数)を 新たに execveargv[0] はインタプリタ、argv[1] 以降にスクリプトパス等が渡されます。
  4. #! なしで ELF/COFF など実行形式でもテキストでもない場合は ENOEXEC。呼び出し元のシェル実装によっては /bin/sh script.sh などへフォールバックすることがあります(ポータビリティは要注意)。
  5. noexec マウント(例:/tmpnoexec)ではここでブロック。たとえ x が立っていても 「実行」自体を禁止できるのがカーネル経路の強みです。

2) bash script.sh(インタプリタ明示)

  1. 親シェルが fork → 子が execve("/bin/bash", ["bash","script.sh"], envp) を発行。
  2. カーネルは **bash バイナリ(ELF)**の実行を許可すれば OK(当然 x 必須)。
  3. 起動した bash 自身がユーザ空間で open("script.sh")read し、内容を bash 文法として解釈・実行。
  4. スクリプトファイルに必要なのは r ビットのみ。shebang は コメント扱い。noexec マウントでも読めれば実行可能(実行しているのは bash バイナリであって、スクリプトは「読み物」だから)。

直接実行 vs インタプリタ実行:比較表(同階層の差分を一望)

基本特性

観点 ./script.sh(カーネル実行) bash script.sh(bash 実行)
要求権限 スクリプトに x(実行) 必須(多くは r も必要) スクリプトは **r(読み取り)**のみで可
shebang カーネルが解釈し、指定インタプリタを exec 無視(コメント)。bash 文法で解析
noexec マウント ブロックされる(実行不可) 回避可能(bash が読むだけ)
エントリポイント スクリプト自身(shebang 経由でインタプリタへ) 常に /bin/bash(または指定の bash)
PATH/ポータビリティ #!/usr/bin/env bash で PATH 解決可 呼び出した bash に依存(shebang無視)

セキュリティ/制御

観点 ./script.sh bash script.sh
SELinux/AppArmor exec トランジションが発生しラベル遷移が効く ファイルは 単なる読み物で遷移対象外になりがち
setuid/capabilities スクリプトの setuid は 無効化が一般的 同左(bash 経由でも昇格しない)
監査(auditd) exec の被疑要因が明確に残りやすい bash 内部実行で粒度が粗くなることあり
マウント制御 noexec で一括抑止が容易 読み取り可能なら実行され得る

運用/デバッグ

観点 ./script.sh bash script.sh
代表エラー Permission denied(x 無/ noexec)、bad interpreter(shebang/改行) Permission denied(r 無)、言語不一致の構文エラー
改行(CRLF)罠 bad interpreter: No such file or directory になりやすい shebang無視のため 表面上動く→潜在バグ温存
shebang オプション #!/usr/bin/env bash -e 等が 正しく効く 効かないset -e 等はスクリプト側で記述)
再現性 shebang で実行系固定 → 高めやすい 呼び出し側 bash に依存 → 環境差異を拾いやすい

パフォーマンス/プロセス

観点 ./script.sh bash script.sh
起動経路 execve(script)→(shebang)→execve(interpreter) execve(bash)open/read(script)
プロセスツリー interpreter が 子として明確 すべて bash の内部に吸収
オーバーヘッド 追加の exec が入る可能性 I/O 読み取り分のオーバーヘッド

実務で効く差分(意思決定のコア)

  1. 配布用スクリプトは「shebang + x ビット + 直接実行」を標準化

    • shebang は可搬性重視なら #!/usr/bin/env bash、再現性重視なら /bin/bash 固定。
    • CI で以下をチェック:shebang あり、改行 LF、権限 0755shellcheck 合格、依存コマンドの存在。
    • こうすることで shebang オプション(-euo pipefail 等)が確実に効く
  2. noexec な領域・権限事情がある現場では一時的に bash script.sh

    • 読み取りさえできれば動く。だが shebang に書いたオプションや別言語指定は効かない。
    • 運用規程として「緊急対応でのみ可・恒常化しない」を明文化すると事故を減らせる。
  3. 言語ミスマッチの防止

    • Python/Node/Perl などは 必ず shebang を正しく書き、x を付与bash script.py の誤実行を撲滅。
    • .sh 拡張子の有無は OS 的には無関係だが、チーム規約で可読性を担保
  4. エラー駆動のトラブルシュート

    • Permission denied → x 無 or noexec の疑い。
    • bad interpreter → shebang のパス/改行(CRLF)/FS 破損を疑う。
    • bash script.sh でだけ成功 → noexec 回避 or shebang/改行の潜在不良。
  5. セキュリティ境界の設計

    • 実行抑止は noexec と x ビットでまず担保。bash script.sh 経路を想定し、ACL/SELinux で読み取り自体を制御する設計も検討。
    • 監査要件が強い場合は 直接実行を標準にし、exec の証跡を取りやすくする。

具体例で腹落ち(最小実験)

# x なし:直接は失敗、bash 経由は成功
printf '#!/usr/bin/env bash\necho OK\n' > /tmp/x.sh
chmod 0644 /tmp/x.sh
/tmp/x.sh        # → Permission denied
bash /tmp/x.sh   # → OK

# CRLF 罠:直接は bad interpreter、bash 経由は通ってしまう
printf '#!/usr/bin/env bash\r\necho CRLF\r\n' > /tmp/crlf.sh
chmod +x /tmp/crlf.sh
/tmp/crlf.sh     # → bad interpreter: No such file or directory
bash /tmp/crlf.sh# → CRLF(動いてしまう)

# 言語不一致:Python を bash で実行すると壊れる
printf '#!/usr/bin/env python3\nprint("py")\n' > /tmp/a.py
chmod +x /tmp/a.py
/tmp/a.py        # → py
bash /tmp/a.py   # → bash: syntax error ...

深掘りポイント(中級者が押さえるべき“地雷”)

  • shebang の引数#!/usr/bin/env -S bash -E -u -o pipefail のように -S で分割引数を許す実装もあります(環境差要確認)。直接実行でのみ効き、bash script.sh では効きません。
  • argv の違い:直接実行では argv[0] がインタプリタに置き換わり、argv[1] にスクリプトパスが入る(shebang の追加引数はさらに前に入る)。$0 の値が運用に影響するツールでは違いが顕在化します。
  • リーダブルな権限制御noexec は強力だが、**読み取りを許せばバイパス(bash 経由)**されます。読み取り禁止(r を落とす)、ディレクトリに 実行権(検索権)x が無いとファイルを開けない点なども組み合わせて制御する。
  • 環境依存の /bin/bash 問題:コンテナ/軽量ディストロでは /bin/bash が無いことも。/usr/bin/env bash を使うか、ランタイムを同梱して再現性を上げる。
  • 監査・可観測性:直接実行は「どのインタプリタで exec されたか」がログで追いやすい。bash 実行は「bash が何を読んだか」を別途監視しないと霧散しやすい。

使い分けの実務指針(ミニフロー)

  1. 配布 or 自動化ジョブ:shebang + x で 直接実行を標準。
  2. 一時ディレクトリ/制約環境:読み取りのみ確保できるなら bash 実行で暫定対応。ただし恒久化しない。
  3. 異言語スクリプト:shebang で実行系を固定、bash <file> は禁止を規約化。
  4. セキュリティ要件強noexec+権限・MAC で直接実行を設計に組み込み、読み取り権限の最小化で bash 経由も抑制。

まとめ(実用スナップショット)

  • 軸は execve か open/read か:前者は x ビットshebang をカーネルが解釈、後者は r ビットbash が解釈
  • マウント/権限/監査の効き方が根本的に違うnoexec は直接実行を止めるが bash 読み込みは止めない。
  • 配布は「shebang + x + 直接実行」を標準:再現性・監査・事故防止で有利。bash script.sh例外運用に留める。
  • デバッグはメッセージで即切り分けPermission denied(x/noexec)、bad interpreter(shebang/改行)、言語不一致(bash 経由)。

この枠組みをチームのコーディング規約と CI チェックに落とし込めば、現場のトラブルは大幅に減らせます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?