🔥

Bashで実行可能なHTMLファイルを作成する

に公開

前置き

皆さんは何かしらの導入スクリプトとして、このようなものを見たことがあるはずです。

$ curl -sSL https://get.example.com/install.sh | bash

危険性については留意が必要ですが、curlで取得したスクリプトをそのままbashに渡して実行することでインストールを簡略化できる便利な方法です。

このURLをさらに短くする方法として、install.shではなくindex.htmlに書いても同じ効果を得られます。
ついでに httpsは省略できるので、以下のように書くこともできます。

$ curl -sSL get.example.com | bash

ただ、このやり方だと https://get.example.comにアクセスした際、当然ながらスクリプトの中身がそのまま(改行なしで)表示されます。

せっかくならドキュメントのように見せたかったので、HTML兼bashスクリプトが実現できないかと考えました。

目標

HTMLファイルの中にbashスクリプトを埋め込んで、

  • ブラウザで表示したときは普通のHTMLページとして表示される
  • curl ... | bashで実行したときはスクリプトとして実行できる

ようなファイルを作成することを目指します。

結論

以下のような書式で実現できます。

#!/bin/bash
:<<"HTML_CONTENT"
<!DOCTYPE html>
<html style="background: #0a0a0a">
<head>
  <!-- Meta tags and styles -->
</head>
<body>
  <!-- Main content -->
  <script>
    document.addEventListener('DOMContentLoaded', () => {
      // Remove bash script content
      document.querySelectorAll('*').forEach(el => {
        [...el.childNodes].filter(n => n.nodeType === 3 && 
          (n.textContent.includes('HTML_CONTENT') || n.textContent.includes('#!/bin/bash')))
          .forEach(n => n.remove());
      });
    });
  </script>
</body>
</html>
HTML_CONTENT

# 以下はBashスクリプト
echo "Bash script is running."

解説

bashスクリプトの中にHTMLを埋め込む

ヒアドキュメントを使います。
ヒアドキュメントは、複数行の文字列を変数に代入するための構文で、以下のように書きます。

cat <<SAMPLE
ここに複数行の文字列
SAMPLE

この例だとcatコマンドに複数行の文字列を渡すことができます。
今回は別に何かのコマンドとして実行したいわけではないので、:コマンドを使って何もしないようにしています。
これでbashで実行できることはクリアできました。

普通のHTMLとして表示する

さて、この状態でブラウザから開くと(当たり前ですが)以下のようにbashスクリプトの中身がそのまま表示されます。

これらのテキストをDevToolsで確認すると、ブラウザからしたら意味不明な文章は テキストノードとして取り扱われていることがわかります。
DevTools

よって、JavaScriptを使って読み込み完了時に当該部分を消しにいけば良さそうです。
HTMLにおいては改行は関係なく一つのテキストノードに突っ込まれるので
HTML_CONTENTを含む = 不要な部分になります。

document.addEventListener('DOMContentLoaded', () => {
  // 読み込み完了時に HTML_CONTENTを含むテキストノードを削除
  document.querySelectorAll('*').forEach(el => {
    [...el.childNodes].filter(n => n.nodeType === 3 && 
      (n.textContent.includes('HTML_CONTENT')))
      .forEach(n => n.remove());
  });
});

一瞬だけ表示されること(ちらつき)を防ぐ

上記のコードを実行すると、ブラウザで開いたときに一瞬だけbashスクリプトの中身が表示されてしまいます。
これを防ぐために、HTMLの<html>タグにstyle="background: #0a0a0a"のように黒系の背景色を指定しておきます。
(その後表示するWebページの背景色に合わせます)

最初は<style>タグ内に書いていたのですが、異常なHTMLのせいなのか <style>タグ内のCSSが適用される前に表示されてしまうようです。
そのため、<html>タグに直接書いています。

成果物

このような感じになります。
https://dotfile.eclairs.cc/

ブラウザから開いた場合

curl ... | bashで実行した場合

余談

なんでこんな形で展開したかという話ですが…

自分用のdotfilesを展開するとき、URLは覚えてるんですがcurlのオプションを忘れがちです。あと都度手打ちしたくない。
そういう時に、覚えてるURLを開く→コピペする→ターミナルに貼り付ける、という手順で実行できるようにしたかった。
それならinstall.shindex.htmlを別々に用意しても良いじゃん、と言われればその通りですが、なんとなくURLを短くしてみたかった。

というのが背景です。

余談の余談

上記内容は、自分のdotfilesを改修してるときに思いつきました。

何をやってたかというと

  • Claude Code
    • alias cc="claude --dangerously-skip-permissions"
    • ついでにSuperClaude
  • playwright-mcp
    • 日本語フォント+絵文字の導入(vlgothicnoto-color-emoji)
    • playwrightのセットアップ(npx playwright install chromium)
      • これを毎回やると重いので、スクリプトだけ用意しておいて必要になったら叩く

を自動で展開する機能です。

vscodeのdotfiles設定欄に↑のURLをセットしておけば、任意のdevcontainerを開いたときに上記セットが自動で展開されます。便利!
中身が気になる方は上記レポジトリを見てみてください。

GitHubで編集を提案

Discussion