同じスクリプトを2か所に置くと、いつか必ず事故る|1か所にまとめる手順

同じスクリプトを2か所に置くと、いつか必ず事故る|1か所にまとめる手順 自動化のはじめ方

自動化がある日いきなり止まったとき、原因が「プログラムの間違い」ではなく「同じものを2か所に置いていたこと」だった、という話をします。

結論を先に書きます。同じ内容を2か所に書いた時点で、いつか片方だけ直して事故ります。気合いや注意深さでは防げません。防ぐ方法は2つだけで、「設定を1つのファイルにまとめて、みんながそこを読む」か、「本体を1つに決めて、もう片方は本体への案内板(シンボリックリンク)に置き換える」かです。どちらもコマンド数行で済みます。

私は清掃業を経営していて、プログラマーではありません。自分の会社の事務を自動化する中で実際にこれをやらかしたので、その記録と直し方を書きます。


朝9時に動くはずの処理が、何も言わずに止まっていた

うちでは毎朝9時に、Macが自動で記事を1本書く仕組みを動かしています。2026年8月27日の朝、それが動きませんでした。

エラーの記録に残っていたのは、たった1行です。

find: ~/Desktop/新規事業/G_メディア事業/記事/wordpress投稿用: Operation not permitted

「Operation not permitted」は「その操作は許可されていません」という意味です。ファイルが無いのではなく、見に行く権限が無いと言っています。

理由はmacOSの仕組みでした。デスクトップ・書類・ダウンロードの3つのフォルダは、macOSが特別に保護しています。自分でターミナルを開いて打つときは許可が下りているのですが、時間になったらMacが勝手に動かす仕組み(launchd)から呼ばれたときは、その許可が下りていません。手で動かすと成功し、自動だと失敗する。いちばん気づきにくい壊れ方です。

そして、この日は記事が1本も作られませんでした。成功したときだけ記録に1行足す作りにしていたので、記録には8月26日の行の次が飛んでいます。つまり「失敗した」と書いてあるのではなく、「何も書いていない」ことでしか気づけない状態でした。

この「止まったのに誰も気づかない」問題そのものについては、別記事で終了コードの話として書いています。今回は原因のほうの話です。

本当の原因は「置き場所が3か所に書いてあった」こと

ここからが本題です。記事のHTMLをデスクトップに置いていたのが直接の引き金ですが、本当に効いていたのは、その置き場所が3つのファイルにバラバラに書いてあったことでした。

書いてあった場所 役割
~/scripts/media/config.sh スクリプトが実際に読む設定
~/scripts/media/README.md 人向けの手順書
~/scripts/media/執筆ルール.md AIに記事を書かせるときの指示書

8月27日の10時48分に、私は控えを取ってから記事フォルダを ~/scripts/media/記事 へ移し、config.sh の1行を書き換えました。これで自動化そのものは復旧しました。

ところが残り2つは、この記事を書いている時点でもまだ古いデスクトップのパスのままです。手順書には今も「記事のHTMLをデスクトップの〜に置く」と書いてあります。まさに「片方だけ直した」状態が、直した本人の目の前で今も残っているわけです。

これが「同じものを2か所に置くと事故る」の正体です。3か所に書けば、直すときに3か所とも思い出さないといけない。1回目は覚えています。3か月後の自分は覚えていません。

逆に、1か所にまとめてあった部分は1行で終わった

救いだったのは、スクリプト側は最初から1か所にまとめてあったことです。うちのメディア用フォルダには実行するスクリプトが5本あり、全部が冒頭でこう書いています。

source "$HOME/scripts/media/config.sh"

「設定はこのファイルから読みます」という1行です。おかげでフォルダを移したとき、5本のスクリプトを1本も触らずに、config.sh の1行だけで引っ越しが終わりました。もし5本それぞれにパスを直書きしていたら、5か所直して、たぶん1か所忘れています。


やり方その1:設定を1つのファイルにまとめる

いちばん簡単で、効果が大きいのはこれです。「あとで変わりそうなもの」だけを別ファイルに追い出すと考えてください。フォルダの場所、サイトのURL、使うPythonの場所などです。

設定ファイルを1つ作ります。

cat > ~/scripts/自分の設定.sh <<'EOF'
#!/bin/zsh
# ここだけ直せば全部に効く

# 作業に使うフォルダ
SAGYOU_DIR="$HOME/scripts/media/記事"

# このMacで動くPython(/usr/bin/python3 は使えない)
PY="$HOME/scripts/keiri/.venv/bin/python"
EOF

使う側のスクリプトは、頭で読み込むだけです。

source "$HOME/scripts/自分の設定.sh"

# 以降は $SAGYOU_DIR や $PY と書けばよい
ls "$SAGYOU_DIR"

これだけで、フォルダを引っ越したときに直すのは設定ファイルの1行になります。

やり方その2:シンボリックリンク(本体への案内板)

設定でまとめられないもの、たとえば「同じ内容のファイルを、どうしても2か所に置きたい」ときはこちらです。

シンボリックリンクは、ファイルの分身ではなく「本体はあっちですよ」という案内板です。案内板を開くと本体が開きます。本体を直せば、案内板の側も自動で同じ内容になります。というより、もともと中身は1つしかありません。

うちで実際に使っている例

うちでは、Claude・Codex・Geminiという3つのAIを使い分けています。この3つは、それぞれ別の場所にある別の名前の指示ファイルを読みに行く決まりになっています。以前はそこに同じ内容を3つ置いていました。当然、1つだけ直して他が古いまま、という状態がすぐ起きました。

今は本体を1つだけ作り、残り3つは全部その本体への案内板にしてあります。

ファイル 実体
~/.ai-shared/共通ルール.md 本体。直すのはここだけ
~/.claude/CLAUDE.md 本体への案内板
~/.codex/AGENTS.md 本体への案内板
~/.gemini/GEMINI.md 本体への案内板

本体を1行直せば、3つのAIが同じ日に同じルールで動きます。「Claudeには伝えたがGeminiには伝え忘れた」が起きません。


コピペで動く:2か所にあるものを1か所にまとめる手順

順番どおりにやってください。控えを取る前にリンクを作らないでください。手順3で片方のファイルを消すので、控えが無いと戻せません。

手順0 同じ名前のファイルが2か所に無いか探す

find ~/scripts -maxdepth 4 -type f \( -name '*.sh' -o -name '*.py' -o -name '*.md' \) -print0 \
  | xargs -0 -n1 basename | sort | uniq -d

同じ名前が2つ以上あるものだけが並びます。何も出なければ、その範囲では重複していません。

手順1 中身が本当に同じか確かめる

diff ~/場所A/ルール.md ~/場所B/ルール.md

何も出なければ中身は同じです。差が出たら、どちらが正しいかを先に決めてください。ここを飛ばすと、古いほうを本体にしてしまいます。

手順2 控えを取る(必須)

cp -p ~/場所B/ルール.md ~/場所B/ルール.md.bak-$(date '+%Y%m%d-%H%M%S')

ファイル名のうしろに日付と時刻が付いた控えができます。

手順3 本体を決めて、もう片方を案内板に置き換える

HONTAI="$HOME/場所A/ルール.md"
LINK="$HOME/場所B/ルール.md"

rm "$LINK"
ln -s "$HONTAI" "$LINK"

ln -s は「案内板を作る」コマンドです。書く順番は「本体 → 案内板」です。逆にすると意味が変わるので、ここだけ気をつけてください。

手順4 ちゃんと案内板になったか確かめる

ls -la ~/場所B/ルール.md

行の最後が ルール.md -> /Users/…/場所A/ルール.md のように矢印付きで表示されれば成功です。中身も見ておきます。

cat ~/場所B/ルール.md

本体の中身が出れば完了です。

元に戻したくなったら

rm ~/場所B/ルール.md
cp -p ~/場所B/ルール.md.bak-20260828-090000 ~/場所B/ルール.md

日付の部分は、手順2でできた控えの名前に合わせてください。案内板を消しても本体は消えません。案内板は中身を持っていないからです。


まとめてはいけないもの、まとめなくていいもの

デスクトップ・書類・ダウンロードの中を本体にしない

今回まさにこれで止まりました。この3つのフォルダはmacOSが保護していて、自動実行の仕組みから呼ばれたときは中を読めません。案内板を張るかどうか以前に、自動化が触るファイルはこの3つのフォルダの外に出してください。うちは ~/scripts/ の下に集約しました。

パスワードや通知先は、まとめずに分けたまま

うちのSlack通知は、メディア用と経理用で通知先のファイルを分けています。まとめれば管理は楽になりますが、片方が漏れたときに両方が漏れますし、記事作成の失敗通知が経理のチャンネルに流れ込みます。共有すると楽になるものと、共有すると被害が広がるものは、分けて考えてください。

バックアップは複製のままでいい

控え(.bak-日付 の付いたファイル)は、まとめてはいけません。複製であること自体が目的だからです。今回も、移す前のフォルダをまるごと固めた控えを残していたので、安心して移動できました。1か所にまとめるのは「常に同じであってほしいもの」だけです。


月に1回、2分でできる点検

引っ越しや名前変更をしたら、古い名前がどこかに残っていないかを検索してください。これが今回いちばん効いた反省です。

grep -rn "古いフォルダ名" ~/scripts --include='*.sh' --include='*.py' --include='*.md'

出てきた行が、まだ直っていない場所です。私はこれを最初にやらなかったので、手順書と指示書が古いまま残りました。1か所直したら、必ずこの検索を1回かける。これだけで「片方だけ直した」はほぼ消えます。

まとめ

  • 同じ内容を2か所に書いた時点で、いつか片方だけ直して事故る。注意力では防げない
  • いちばん効くのは設定ファイルを1つ作り、全スクリプトがそこを読む形にすること。うちはこれのおかげで、フォルダ引っ越しが設定1行で済んだ
  • ファイルそのものを共有したいときはシンボリックリンク。本体を1つ決めて、残りは案内板にする
  • 作業前に必ず控えを取る。ln -s は「本体 → 案内板」の順
  • 自動化が触るファイルをデスクトップ・書類・ダウンロードに置かない。自動実行だと読めない
  • パスワードや通知先はまとめない。控えもまとめない
  • 直したあとは grep で古い名前を1回検索する

今日やるなら、手順0の検索コマンドを1回打ってみるところからで十分です。同じ名前のファイルが2か所に出てきたら、それが次に事故る場所です。

今回のように「動いていないのに誰も気づかない」状態そのものを潰す話は、launchdが動かない・終了コード127の原因と対処にまとめてあります。自動実行が絡む不具合は、まずこちらを見てください。

コメント

タイトルとURLをコピーしました