Communityライティング&編集github.com

pwquint24/org-babel-shell

Org Babelを使ったシステム自動化、DevOps、リモート実行、シェルスクリプティング(Bash、Zsh、Fish、Dash、Sh)の完全ガイド。

org-babel-shell とは?

このスキルは、OrgモードのOrg Babelフレームワークでシェルコードブロックを最大限に活用するための包括的なガイドです。Bash、Zsh、Fish、Dash、Shなど、複数のUnix/POSIXシェルをサポートし、Emacs上でインタラクティブなDevOpsノートブック、システム管理コンソールとして機能します。このスキルは、通常のサブシェル実行、永続的なcomintセッション、非同期バックグラウンド実行の3つの実行モードを提供し、`:stdin`、`:cmdline`、`:shebang`といったシェル固有のヘッダー引数もサポートします。また、TRAMP経由のリモートサーバー管理、結果のOrgテーブルへの解析、`:async yes`によるノンブロッキング実行など、高度な機能も網羅しています。Emacs上で動作し、DevOps、システム管理、インフラ自動化タスクに特に有効です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pwquint24/org-babel-agent-skills/tree/HEAD/skills/org-babel-shell

Installed? Explore more ライティング&編集 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Org Babel でのシェル&Bashコードブロック

Org Babelは、UnixおよびPOSIXシェル(Bash、Zsh、Sh、Fish、Dash、Csh、Ksh、Ash)を幅広くサポートしています。

シェルブロックを使うと、OrgモードがインタラクティブなDevOpsノートブック、ランブック、システム管理コンソールに変わり、ローカル実行、バックグラウンド非同期処理、TRAMP経由のSSHリモートサーバー管理が可能になります。


1. 要件と設定

1.1 Emacsの設定

他のBabel言語のように別個のモジュールを必要とせず、すべてのシェルは単一のBabelライブラリ(ob-shell)で管理されます。org-babel-load-languages に (shell . t) を追加するだけで使用できます。

(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (shell      . t)))

(注: Org 8.2より前は sh という名前でした。最新のOrgバージョンでは常に shell を使用してください。)

1.2 シェルの指定

ブロック言語タグ(#+BEGIN_SRC <shell>)で使用するシェルのバイナリ名を正確に指定します。

# Bash:
#+BEGIN_SRC bash
  echo "Running in $BASH_VERSION"
#+END_SRC

# Zsh:
#+BEGIN_SRC zsh
  echo "Running in Zsh $ZSH_VERSION"
#+END_SRC

# POSIX / Dash (高速、軽量実行):
#+BEGIN_SRC dash
  echo "Running in dash"
#+END_SRC

# Fish shell:
#+BEGIN_SRC fish
  set greeting "Hello from fish"
  echo $greeting
#+END_SRC

指定したシェルのバイナリがシステムの $PATH 上でアクセス可能である必要があります。


2. 実行モード: 独立サブシェル、セッション、非同期

2.1 独立サブシェル(デフォルト、:session none)

各ブロックは新しい一時的なサブシェルプロセスで実行されます。環境変数や作業ディレクトリは引き継がれません。

#+BEGIN_SRC bash :results output
  echo "PID: $$"
  export WORKSPACE="/tmp/build"
#+END_SRC

#+BEGIN_SRC bash :results output
  # 新しいサブシェルで実行されるため、$WORKSPACE は空です:
  echo "PID: $$, WORKSPACE: $WORKSPACE"
#+END_SRC

2.2 インタラクティブセッション(:session <名前>)

永続的なEmacs comint バッファ(例:*dev-session*)内で実行されます。変数、関数、作業ディレクトリが複数のブロック間で保持されます。

#+BEGIN_SRC bash :session *dev-session* :results output
  export CLUSTER_ID="prod-east-01"
  cd /var/log
#+END_SRC

#+BEGIN_SRC bash :session *dev-session* :results output
  # 前のブロックで設定された状態を使用:
  echo "Deploying to $CLUSTER_ID from $(pwd)"
#+END_SRC

#+RESULTS:
: Deploying to prod-east-01 from /var/log

2.3 ノンブロッキング非同期実行(:async yes)

長時間実行されるスクリプト(バックアップ、コンテナビルド、モデルトレーニング)は同期実行するとEmacsをフリーズさせます。:async yes を追加すると、バックグラウンドで実行され、エディタをロックしません!

ルール:

  1. :async には :session <名前> が必須です。
  2. 実行中、Babelは #+RESULTS: ブロックに一時的なUUIDトークンを挿入します。
  3. バックグラウンドで実行が完了すると、UUIDは自動的にコマンドの標準出力に置き換えられます。
#+BEGIN_SRC bash :session *bg-job* :async yes :results output
  echo "Starting heavy database backup at $(date)..."
  sleep 5
  echo "Backup finished successfully at $(date)!"
#+END_SRC

#+RESULTS:
: Starting heavy database backup at Sun May 18 14:00:00 UTC 2025...
: Backup finished successfully at Sun May 18 14:00:05 UTC 2025!

セッション内で同期的に実行するには、:async no を指定します。


3. シェル固有のヘッダー引数

Org Babelは、シェル操作に特化した3つのユニークなヘッダー引数を提供します。

3.1 :stdin <要素名>(標準入力)

名前付きOrg要素(テーブル、生テキスト、他のコードブロックの結果)をシェルコマンドの標準入力にパイプします。

# 生テキスト入力:
#+NAME: raw_server_payload
{"node": "alpha", "cores": 8, "status": "active"}

# ペイロードをjqに直接パイプ:
#+BEGIN_SRC bash :stdin raw_server_payload :results output
  jq -r '.node + " has " + (.cores|tostring) + " cores"'
#+END_SRC

#+RESULTS:
: alpha has 8 cores

(注: :stdin を使用するブロックは、:session を無視して一時的なサブシェルで評価されます。)

3.2 :cmdline <引数>(コマンドライン引数)

位置引数($1、$2、$@)をスクリプト本体に渡します。

#+BEGIN_SRC bash :cmdline "staging" 8080 :results output
  ENV="$1"
  PORT="$2"
  echo "Starting server on port $PORT in $ENV mode..."
#+END_SRC

#+RESULTS:
: Starting server on port 8080 in staging mode...

⚠️ セキュリティ警告: :cmdline の引数はホストシェルによって直接展開されます。コマンドインジェクションを防ぐため、信頼できない文字列やエスケープされていない文字列を渡さないでください。

3.3 :shebang <ディレクティブ>(スタンドアロンスクリプトとクリーンな出力)

ブロックを一時的な実行可能ファイルに書き込み、そのshebangディレクティブを介して実行するように強制します。

#+BEGIN_SRC bash :shebang "#!/usr/bin/env bash" :results output
  for i in {1..3}; do
      echo "Step $i"
  done
#+END_SRC

:shebang が重要な理由: 複数行の :session ブロックでshebangがない場合、行はインタラクティブシェルに1行ずつ送信され、結果に不要なプロンプト文字列(例:bash-5.1$ )が含まれる可能性があります。:shebang を指定するか、セッションなしで実行すると、完全にクリーンな出力が得られます。


4. TRAMP経由のリモートサーバー管理(:dir)

:dir にTRAMPパスを指定することで、リモートサーバー、仮想マシン、Dockerコンテナ上でコマンドを実行できます。

:dir /ssh:<ユーザー>@<ホスト>:<リモートパス>
:dir /docker:<コンテナID>:<パス>
:dir /sudo::/etc

例: リモートシステム管理ワークフロー

# リモートサーバーのディスク使用量とメモリを確認:
#+BEGIN_SRC bash :dir /ssh:[email protected]:/tmp :results output
  hostname
  uptime
  df -h / | awk 'NR==2 {print "Root Disk Usage: " $5}'
#+END_SRC

#+RESULTS:
: bastion.example.com
: 14:22:05 up 42 days,  3:18,  1 user,  load average: 0.12, 0.08, 0.05
: Root Disk Usage: 48%

リモートセッション

:dir と :session を組み合わせると、各ステップで再接続することなく、複数のブロック間でアクティブなSSH接続を維持できます。

#+BEGIN_SRC bash :dir /ssh:[email protected]:/home/admin :session *remote-bastion* :results output
  WORKDIR=$(mktemp -d)
  cd "$WORKDIR"
  pwd
#+END_SRC

5. 結果フォーマットと表形式データ抽出

5.1 タブ区切り出力をOrgテーブルに変換(:results output table)

シェルコマンドがタブ区切りまたは構造化された表形式の出力を生成すると、BabelはそれらをネイティブのOrgテーブルにパースします。

#+BEGIN_SRC bash :results output table
  printf "PID\tUser\tCommand\n"
  printf "101\troot\tsystemd\n"
  printf "405\tpostgres\tpostgres\n"
  printf "892\tnginx\tnginx: worker\n"
#+END_SRC

#+RESULTS:
| PID | User     | Command       |
|-----+----------+---------------|
| 101 | root     | systemd       |
| 405 | postgres | postgres      |
| 892 | nginx    | nginx: worker |

5.2 出力をファイルリンクにリダイレクト(:results file :file <パス>)

#+BEGIN_SRC bash :results file :file reports/sysinfo.txt
  uname -a > reports/sysinfo.txt
  cat /etc/os-release >> reports/sysinfo.txt
#+END_SRC

#+RESULTS:
[[file:reports/sysinfo.txt]]

6. 変数とBash配列の受け渡し(:var)

6.1 スカラーと文字列

#+BEGIN_SRC bash :var port=8000 host="localhost" :results output
  echo "Connecting to $host on port $port..."
#+END_SRC

6.2 Bash 1次元配列

Bashは、リスト構文で定義された1次元配列パラメータをサポートしています。

#+BEGIN_SRC bash :results output :var servers='("web-01" "web-02" "db-01")'
  echo "Total servers: ${#servers[@]}"
  for s in "${servers[@]}"; do
      echo "Pinging $s..."
  done
#+END_SRC

#+RESULTS:
: Total servers: 3
: Pinging web-01...
: Pinging web-02...
: Pinging db-01...

7. よくある落とし穴と安全のベストプラクティス

落とし穴原因解決策
EmacsがSSHやffmpegコマンドでハングアップコマンドがサブシェルの標準入力を読み取ろうとする標準入力を明示的にリダイレクトする(</dev/null)か、ssh -n を使用する。
結果に bash-5.1$ などのプロンプト文字が含まれる:session 内でのインタラクティブな1行ごとのエコー:shebang #!/usr/bin/env bash を追加するか、セッション外で評価する。
ヒアドキュメント内での意図しない変数展開<<EOF を使用するとシェルが $VARS を早期に展開する引用符で囲まれたデリミタ <<"EOF" を使用してテキストをリテラルに保ち、早期展開を防ぐ。
sh ブロックでPOSIX非互換の構文が失敗する#+BEGIN_SRC sh は /bin/sh(Debian/Ubuntuではdash)にマッピングされるスクリプトでbashism([[、((、配列)を使用する場合は #+BEGIN_SRC bash を使用する。
:cmdline によるコマンドインジェクションシェル引数がそのまま評価される引数を注意深く引用符で囲むか、代わりに :stdin や :var を使用してデータを渡す。
非同期ブロックの出力が表示されない:async yes にはアクティブな :session が必要:async yes を使用する場合は常に :session <名前> を指定する。

8. 完全なDevOpsランブックの例

#+TITLE: 本番サービスヘルスランブック
#+PROPERTY: header-args:bash :session *runbook* :results output

* ステップ 1: ヘルスチェック設定
#+NAME: cluster_nodes
| Hostname        | Role    |
|-----------------+---------|
| prod-app-01.lan | backend |
| prod-app-02.lan | backend |
| prod-db-01.lan  | storage |

* ステップ 2: クラスタノードのプローブ
#+BEGIN_SRC bash :var nodes=cluster_nodes :colnames yes :results output table
  printf "Host\tRole\tStatus\n"
  for row in "${nodes[@]}"; do
      # タブ/スペース区切りの行データをパース:
      host=$(echo "$row" | awk '{print $1}')
      role=$(echo "$row" | awk '{print $2}')
      
      # 簡易pingプローブ:
      if ping -c 1 -W 1 "$host" > /dev/null 2>&1; then
          status="ONLINE"
      else
          status="OFFLINE"
      fi
      printf "%s\t%s\t%s\n" "$host" "$role" "$status"
  done
#+END_SRC

#+RESULTS:
| Host            | Role    | Status |
|-----------------+---------+--------|
| prod-app-01.lan | backend | ONLINE |
| prod-app-02.lan | backend | ONLINE |
| prod-db-01.lan  | storage | ONLINE |

* ステップ 3: サービスメンテナンスを非同期実行
#+BEGIN_SRC bash :session *runbook* :async yes
  echo "Initiating rolling cache purge across nodes..."
  sleep 4
  echo "Cache purge completed successfully."
#+END_SRC

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

関連スキル