◉ANTIGRAVITY LABEN
記事一覧/Tips & 活用術
✦ Tips & 活用術/2026-10-30初級

Linux で通った sed -i が iMac で止まった夜。エージェントの手順書を手元で動かす前の確かめ方

Linux の環境で動いた sed -i の手順を iMac で実行すると、置き換えが止まったり、バックアップが散らかったりします。GNU 版で再現した出力と、どちらでも動く書き方、実行前の確かめ方をまとめました。

sedmacOSシェルスクリプト5エージェント運用20個人開発122Antigravity406

サーバー側の設定値をまとめて書き換える手順を、エージェントに作ってもらった夜のことです。Linux の環境ではすんなり動いたので、同じ手順をそのまま香川の自宅の iMac にも流しました。

ところが、置き換えは一行も進まず、ターミナルには見慣れないエラーが一つ出ただけでした。原因は、sed -i という短いオプションの書き方の違いでした。

個人開発で壁紙アプリの配信まわりを触っていると、サーバー(Linux)と手元の iMac を行き来する手順が日常になります。エージェントが返す手順書には、Linux で動くことを前提にした書き方がよく混ざります。その手順を自分の Mac で動かす前に、何を見ればよいか。小さな再現とあわせて、書き残します。

最初にお伝えしたいのは、「動いた」の置き場所です

あの夜の私は、Linux で動いたことを「手順が正しい」ことの証拠にしていました。いま思えば、確かめた場所を取り違えていたのだと思います。しかし、動いたのは手順ではなく、その手順と、その環境の組み合わせです。

sed のように同じ名前でも中身が違うコマンドは、組み合わせが変わると結果が変わります。macOS に入っている sed と、Linux で一般的な GNU 版の sed は、その代表例です。

何が違うのか、まず手元で再現しました

今回の再現は、手元の Linux 環境(GNU 版の sed 4.8)で行いました。macOS 側は実機で測っていないため、そちらは公式のマニュアルにある仕様として書きます。

設定ファイルを一つ用意して、old を new に置き換えます。

printf 'API_HOST=old.example.com\nMODE=old\n' > app.env
sed -i 's/old/new/' app.env
cat app.env

GNU 版では、これで二行とも new に変わります。ファイル名も増えません。

次に、macOS 向けの書き方として知られる「-i の直後に空の文字列を置く」形を、同じ Linux で流してみました。

sed -i '' 's/old/new/' app.env

結果は次のとおりでした。

sed: can't read s/old/new/: No such file or directory

終了コードは 2、ファイルの中身は old のままです。GNU 版は '' を「空のスクリプト」と読み、続く s/old/new/ をファイル名として開こうとして失敗した、ということです。

つまり、同じ -i でも、続く引数の意味が環境で違います。Linux 向けの短い形を Mac に持ち込めば止まり、Mac 向けの形を Linux に持ち込んでも止まります。

書き方GNU 版(手元で実測)macOS 同梱の sed(マニュアル上の仕様)
sed -i 's/old/new/' f置き換わる(終了コード 0)「s/old/new/」を拡張子と読み、次の引数をスクリプトとして解釈しようとするため、エラーになる
sed -i '' 's/old/new/' f失敗する(終了コード 2・内容は変わらない)置き換わる
sed -i.bak 's/old/new/' f置き換わる(f.bak が残る)置き換わる(f.bak が残る)

表の三行目だけが、どちらでも同じ意味になります。ここが今回の出口です。

どちらでも動く書き方は、三つあります

一つ目は、拡張子をくっつけて書く -i.bak の形です。GNU 版でも f.bak を残して置き換わり、macOS でも同じ動きになります。

二つ目は、perl -pi -e を使う方法です。同じ設定ファイルで試すと、置き換わり、余計なファイルも増えませんでした。

perl -pi -e 's/old/new/' app.env

perl は macOS にも最初から入っているため、手順書を使い回したいときには気楽です。ただし、正規表現の細かな書き方は sed と少し違うので、複雑な置き換えは別途確かめてください。

三つ目は、そもそも「どちらの sed か」を先に判定する書き方です。

if sed --version >/dev/null 2>&1; then
  SED_INPLACE=(sed -i)        # GNU 版
else
  SED_INPLACE=(sed -i '')     # macOS 同梱の版
fi
"${SED_INPLACE[@]}" 's/old/new/' app.env

--version は GNU 版にはありますが、macOS 同梱の版にはない、という違いを使っています。判定してから使うので、手順書の書き手がどちらの環境を想定していたかに左右されません。

バックアップを使うなら、後始末まで手順に入れます

-i.bak は安全ですが、一つ気をつけたい点があります。ファイルが増えるのです。三つのファイルに流すと、元のファイルに加えて .bak が三つできました。ディレクトリのファイル数が 5 から 8 に増え、後始末の rm で 5 に戻りました。

Git のリポジトリで流したときは、変更されたファイルの横に、追跡されていない .bak が並びました。

 M g1.txt
 M g2.txt
 M g3.txt
?? g1.txt.bak
?? g2.txt.bak
?? g3.txt.bak

そのまま git add . をすると、バックアップごと記録されてしまいます。自分のサイトのリポジトリで一度やりかけて、気づいたのはコミットの直前でした。置き換えの一行のすぐ後ろに、後始末の一行を並べておくのが私のやり方です。

sed -i.bak 's/old/new/' g*.txt && rm -f g*.txt.bak

また、macOS 側でよく聞く落とし穴として、-i -e と書くと、-e が拡張子として読まれ、ファイル名-e というバックアップが生まれる、というものがあります。GNU 版で同じ書き方を流すと、余計なファイルは増えませんでした。環境によって結果が違う典型なので、-i -e の形は避けるようにしています。

エージェントに頼むときは、環境を一言添えます

ここまでの確かめを、毎回自分の頭でやるのは大変です。そこで、依頼の文に環境を一言添えるようにしました。

この手順は macOS(iMac)と Linux の両方で動かします。
sed の -i は、どちらでも同じ意味になる -i.bak の形にして、
置き換えの直後にバックアップを削除する行も入れてください。

これだけで、返ってくる手順の癖がかなり揃うかもしれません。少なくとも私の手元では、手戻りが減ったと感じています。それでも、手元で流す前には、置き換え対象のファイルを一つだけ選んで、先に試します。

動いたのは手順ではなく、手順と環境の組み合わせです。 この一文を、手順書を受け取るたびに思い出すようにしています。

次にエージェントから sed -i を含む手順を受け取ったときは、まず -i の直後がどうなっているかだけ見てみてください。そこが -i.bak か perl -pi でなければ、一ファイルで試してから全体に流すところから始めていただければと思います。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

✦ Tips & 活用術2026-10-19
URL を書き換えたら、あとから読み込む画像だけ 404 になりました。replaceState と相対パスの確かめ方
一覧から個別表示へ切り替えるとき history.replaceState で URL を書き換えたところ、まだ読み込んでいない画像だけが 404 になりました。loading=lazy も同じ挙動だった点、確認用の最小ページとスクリプト、直し方三種の比較までを書き残します。
✦ Tips & 活用術2026-10-17
検索の管理画面に「ページにリダイレクトがあります」と出たとき、直すものと放っておくものを分けた基準
Search Console の「ページにリダイレクトがあります」を、自分のサイトで仕分けた記録です。http→https・www・末尾スラッシュ・言語の振り分けは想定内、チェーン・ループ・転送先のエラーや noindex は要対応という線引きと、転送を一つずつ辿って分類する Python スクリプト、素の要求では見えない言語依存の転送を二通りの要求で見つける方法まで書き残します。
✦ Tips & 活用術2026-10-15
画像が壊れて見えたのは、確かめ方のせいでした。iframe 検証を疑う順番と、実ページの currentSrc
別タブの iframe に実ページを差し込んで画像を点検し、「読み込まれていない」と誤診した失敗の記録です。非表示の枠では描画幅 0 のまま naturalWidth が 0 になり、遅延読み込みは未開始のまま残ります。手元で再現した数値と、実ページで currentSrc と描画幅を見る検査スクリプト、置換を正規表現で機械的に行ったときの落とし穴まで書き残します。