AI活用#zsh for 変数 分割されない

zshのforで変数が分割されない原因と直し方|41件消えた実録【2026年】

机を上から見た図で、ひもで1つに束ねられた札の束と、ばらばらに並んだ札と、札の入った書類箱があり、会社員と小さなロボットが札を仕分けているイラスト
イラスト:AIで作成

この記事の結論

zshのforで変数が分割されないのは、不具合ではなくzshの既定の仕様です。AIが書いた選別削除のコマンドで、6件残すはずの下書き41件が全部消えた当社の実録と、配列での直し方、削除の前に対象を一覧で出す手順をまとめました。

目次6項目
  1. zshのforで変数が分割されないのは、zshの既定の仕様
  2. zshで変数を分割して回す3つの直し方
  3. 裏方で実際に起きた例:2026年9月、6件残すはずの下書き41件が全部消えた
  4. AIに選別削除を頼むときの再発防止:配列と事前の一覧
  5. 業務でAIにファイルの一括処理を任せるときの注意
  6. よくある質問

【実践講座】Claude Code 2daysセミナー(第二の脳構築講座)の詳細を見る →

zshのforで変数が分割されないのは、不具合ではなくzshの既定の仕様です。空白で区切ったリストは1語として扱われます。直し方は、リストを配列で持つことです。当社は2026年9月、AIが書いた選別削除のコマンドでこれを踏み、6件残すはずの下書き41件を全部消しました。

zshのforで変数が分割されないのは、zshの既定の仕様

zshとは、Macのターミナルで文字のコマンドを受け取り、実行する役目のプログラム(シェル)の一種です。Appleのサポートページによると、macOS 10.15以降のMacは、zshを標準のシェルとして使います。それより前の標準はbashでした。

問題になるのは、次の形のコマンドです。

LIST="a b c"
for x in $LIST; do echo "[$x]"; done

bashでは [a] [b] [c] の3行が出ます。zshでは [a b c] の1行だけが出ます。エラーは出ません。警告も出ません。ループが3回ではなく1回だけ回り、そのまま終わります。

単語分割とは、変数の中身を空白の位置で切り、複数の語として扱うシェルの動作のことです。zshの公式FAQは、多くのシェルが行うこの分割をzshは既定で行わず、変数はそのまま保たれると説明しています。あわせて、これはバグではないと明記しています。

書き方ごとの違いを表にします。出力は、当社のMacで2026年10月12日に実行して確かめたものです。

書き方zshでの回数bashでの回数
LIST="a b c" を for x in $LIST で回す1回(a b c が1語)3回
LIST=(a b c) を for x in $LIST で回す3回(書き方が異なるため対象外)
LIST="a b c" を for x in ${=LIST} で回す3回(zsh専用の書き方)
setopt shwordsplit の後に for x in $LIST で回す3回(zsh専用の設定)

怖いのは、表示するだけのコマンドではありません。「このリストに載っているものは残し、それ以外は消す」という選別に使ったときです。リストが1語になると、どのファイル名とも一致しません。すると、全部が「残すリストに無いもの」と判定されます。

zshで変数を分割して回す3つの直し方

zshの公式FAQとマニュアルに載っている直し方は3つです。おすすめの順に並べます。

  1. リストを配列で持つ。 配列とは、複数の値を1つずつ区切ったまま、1つの名前で持てる変数の形のことです。LIST=(a b c) と丸かっこで書きます。zshの公式FAQは、zshで語を分けたいときの自然な方法は配列だと案内しています。
  2. その変数だけを分割する。 ${=LIST} と書くと、その場所でだけ分割されます。公式マニュアルは、この書き方が区切りに IFS という設定の値を使うと説明しています。
  3. 設定で分割を有効にする。 setopt shwordsplit を実行すると、bashなどと同じ動作になります。公式マニュアルでは SH_WORD_SPLIT というオプションです。

僕は1番をすすめます。配列なら、空白を含むファイル名も1つの値として持てます。2番と3番は、空白で切る動作に戻すだけなので、名前に空白のあるファイルが2つに割れます。

あなたのターミナルで安全に確かめるなら、次の2行を貼ってください。画面に文字を出すだけで、ファイルには触れません。

LIST="a b c"; for x in $LIST; do echo "[$x]"; done
LIST=(a b c); for x in $LIST; do echo "[$x]"; done

1行目が [a b c] の1行、2行目が3行なら、そのターミナルはzshの既定の動作です。いま動いているのがzshかどうかは、echo $ZSH_VERSION でも分かります。版の数字が出ればzshです。

選別の形でも確かめられます。次の例も表示だけです。

KEEP=(memo_01 memo_02)
for f in memo_01 memo_02 memo_03; do
  hit=no
  for k in $KEEP; do
    if [ "$f" = "$k" ]; then hit=yes; fi
  done
  echo "$f 残す=$hit"
done

当社のMacのzshでは、memo_01 と memo_02 が 残す=yes、memo_03 が 残す=no と出ました。1行目を KEEP="memo_01 memo_02" に変えると、3つとも 残す=no になります。これが、次の章の事故と同じ形です。

裏方で実際に起きた例:2026年9月、6件残すはずの下書き41件が全部消えた

ここからは、僕の会社(株式会社UrakaTA)の失敗の記録からの転記です。

2026年9月5日、社内で使っているツールに、テスト用の下書きが41件たまっていました。このうち6件だけを残し、残りを消す作業を、Claude Codeで進めていました。Claude Codeとは、ターミナルやデスクトップアプリから、AIのClaudeにファイルの操作やコマンドの実行まで任せられるツールです。

組み立てられたコマンドは、残す6件の名前を、空白で区切った1つの文字列として持つ形でした。その文字列をforで回し、名前が一致したものを「残す」と判定する作りです。bashなら、意図どおり6回まわります。

実際に動いたのはzshでした。6件分の名前は1語として扱われ、41件のどれとも一致しません。全件が「残す対象ではない」と判定され、41件すべてが削除されました。エラーは1つも出ていません。コマンドは正常に終わっています。

消えた中には、社内の資料が例として参照していた下書きも含まれていました。どれも再生成できるテスト用のデータだったので、作り直して、資料の参照を貼り直しました。復旧にかかった時間は記録に残していないので、ここには書きません。

原因は2つありました。1つは、bashの書き方をそのままzshで使ったことです。もう1つは、削除の前に「何が消えるのか」を一覧で出していなかったことです。一覧を出していれば、6件が残る側に入っていないことに、その場で気づけました。

AIに選別削除を頼むときの再発防止:配列と事前の一覧

この件のあと、当社の記録に残した決まりは4つです。

  • 残すリストは配列で書く。 文字列で持つなら ${=変数} の形で分割する。
  • 削除の前に、対象の一覧を表示する。 dry-runとは、実際の削除や移動を行わず、対象だけを表示して確かめる試し実行のことです。これを必ず挟みます。
  • 再生成できるデータでも、確認を省かない。 ほかの資料やテストが参照しているものは、消す前に確かめます。
  • Claude CodeのBashは、zshで動く前提で書く。

選別削除の一覧は、次の形で出せます。消す予定のものを表示するだけで、まだ何も消しません。memo_* の部分は、あなたのフォルダにある対象の名前の形に置き換えてください。一致するファイルが無いと、zshは no matches found と出して止まります。

KEEP=(memo_01 memo_02)
for f in memo_*; do
  hit=no
  for k in $KEEP; do
    if [ "$f" = "$k" ]; then hit=yes; fi
  done
  if [ "$hit" = no ]; then echo "消す予定: $f"; fi
done

表示された件数と名前が、あなたの想定と合っているかを見ます。合っていたときだけ、echo "消す予定: $f" の部分を削除のコマンドに置き換えて実行します。件数が「全部」になっていたら、そこで止めてください。

コマンドを自分で読めなくても、AIへの頼み方で同じことができます。依頼文に、次の2行を添えます。

このMacのシェルはzshです。リストは配列で書いてください。
削除や移動の前に、対象と残すものを件数つきの一覧で見せて、私の返事を待ってください。

毎回書くのが手間なら、Claude Codeが作業のたびに読む指示書(CLAUDE.md)に同じ内容を書いておきます。当社も、失敗の記録に「削除系は先に対象一覧を出す」と残し、次の作業から参照させています。

Claude Codeのほかの困りごとは、Claude Codeのエラー・困りごと一覧から症状で引けます。

業務でAIにファイルの一括処理を任せるときの注意

Claude Codeがどのシェルで動くかは、環境で確かめます。 公式ドキュメントは、Claude Codeがセッションの最初に、使っているシェルに応じて ~/.zshrc、~/.bashrc、~/.profile のいずれかを読み込むと説明しています。「Bashという名前のツールだからbashで動く」とは書かれていません。当社のMacでは、zshで動いていました。あなたの環境では、AIに echo $ZSH_VERSION を実行させて確かめてください。

エラーが出ないことは、正しく動いた証拠になりません。 今回のコマンドは正常に終わっています。AIの「完了しました」という報告も、うそではありません。判定の条件は、報告ではなく、消す前の一覧と消した後の件数に置きます。

削除の許可は、一覧を見てから出します。 Claude Codeは、コマンドの実行前に許可を求める設定にできます。許可の画面が何度も出て困る場合の整え方は、Claude Codeで許可の確認が何度も出るときの対処に書きました。削除を含むコマンドを、確認なしで通る設定にしないことをおすすめします。

戻せる場所で作業します。 ターミナルの削除は、ごみ箱を通りません。当社の件は再生成できるデータでしたが、写真や契約書のように作り直せないものなら、復旧できませんでした。作り直せないファイルを選別するときは、先にフォルダごとコピーを取ってから始めてください。

チームで使うなら、決まりを指示書に書いて共有します。 人によって頼み方が違うと、確認を挟む人と挟まない人が出ます。「削除の前に一覧」を各自の気づかいに任せず、共通の指示書に書いておきます。AIに任せた作業でのほかの失敗は、AI導入の失敗事例にまとめています。

当社が確かめたのは、自社のMacでの1件です。 2026年10月時点の公式ドキュメントと、当社の記録にもとづいて書いています。別の環境や設定では動きが違う可能性があります。

AIにファイルの整理やコマンドの実行を任せるときの、指示書の書き方、確認の挟み方、任せてよい範囲の決め方を自社で回せる形にしたい方には、下のセミナーで具体的な作り方をお伝えしています。

よくある質問

zshのforで変数が分割されないのは不具合ですか?

不具合ではありません。zshの公式FAQは、空白を含む変数をクオートなしで書いても分割しないのが既定の動作で、バグではないと明記しています。分けたいときは、リストを配列で持つか、その変数だけを分割する書き方を使います。

bashと同じように分割させる設定はありますか?

あります。SH_WORD_SPLITというオプションを有効にすると、bashなどと同じように分割されます。ただしzshの公式FAQは、分割したいときの自然な方法は配列だと案内しています。設定に頼るより、リストを配列で書くほうが、環境が変わっても同じ結果になります。

AIにファイルの一括削除を頼むとき、何を伝えればよいですか?

「zshで動く前提で、リストは配列で書く」「削除の前に、消す対象と残す対象を一覧で見せる」の2つを依頼文に添えます。当社は2026年9月に、この確認を挟まなかったために、6件残すはずの下書き41件を全部消しました。

引用元・参考にした記事

  1. Chapter 3: How to get various things to work出典Z-Shell Frequently-Asked Questions参照
  2. 16 Options (zsh)出典The Z Shell Manual参照
  3. 14 Expansion (zsh)出典The Z Shell Manual参照
  4. zshをMacのデフォルトシェルとして使う出典Apple サポート参照
  5. Tools reference出典Claude Code Docs参照

Build Your
Second Brain.

Claude Code 2daysセミナー(第二の脳構築講座)、参加受付中。