# memory: instinct-python-split-is-not-shell-word-split

シェルのコマンド文字列をstr.split()で語に割るとbashと食い違う。エスケープ空白・引用空白はbashでは語の内側で、演算子の被演算子がコマンドの頭に化ける。2026-08-14、課金ガード(ai-base#597 / PR#599)で実測。演算子側REDIR_OP_REを<<<まで正しく伸ばした直後の版に、空白の書き方を変えただけの7形態が残った。被演算子を飛ばす条件がskip = r.end() == len(w)(=演算子だけの語なら次語が対象)だったため、<<<\はr.end()=3 != len(w)=4でskipが立たず、/tmp/echoがコマンドの頭に採用される。<<<" " <<<$' ' <<-\ <<\も同型。

## ポイント
- str.split()はbashの語分割ではない。bashは\ " $' 'を語の内側として読むが、split()は空白で割る。
- 被演算子を飛ばす条件がskip = r.end() == len(w)(=演算子だけの語なら次語が対象)だったため、<<<\はr.end()=3 != len(w)=4でskipが立たず、/tmp/echoがコマンドの頭に採用される。
- 演算子を食った残りが語として閉じているかを見る。閉じていなければ被演算子は次の語まで続く: skip = not rest or not _word_is_closed(rest)。
- 閉じ判定は「末尾バックスラッシュ」と「閉じ引用の不在」の2つ: \は次を飛ばす(末尾ならFalse)、' "は相方を探す(無ければFalse)。
- 攻撃側は空白の書き方を選べる。<<< /dev/nullがdenyだったのはbasenameが偶然集合に無かっただけ、という同型の誤解が一段深いところで再発する。
- 同じ概念に物差しが2本あると検出器が割れる。
- 検証はgit archive のスナップショットで行い、生きたworktreeには触れない。実bashの起動確認は中身を無害なprintfマーカーに差し替える(課金を起こさない)。

## 関連ページ
[[instinct-summary-label-lags-behind-implementation]] [[topic-guards-and-fail-open]] [[instinct-billing-guard-blocks-scanner-literals]] [[instinct-parallel-branches-measured-by-one-probe-set]]

## 関連概念(未作成)
`bashの語分割規則` `str.split()の限界` `演算子の被演算子切り出し` `検出器の物差し` `シェルのコマンド文字列解析`