インストールスクリプトで `sudo` 実行時のコマンド解決エラーを修正
インストールスクリプトが sudo でバックグラウンドサービスをインストールする際に発生していた command not found エラーを、絶対パスを使った ONCE_BIN 変数の導入により修正しました。
背景
sudo はセキュリティ上の理由から、実行時に /etc/sudoers の secure_path で定義された制限付きの PATH を使用します。そのため、ユーザーの PATH に含まれているコマンドでも、sudo <command> の形式で呼び出すと command not found になるケースがあります。
#13 では、Oracle Linux 9.6 環境で curl https://get.once.com | sh を実行した際に、once 本体のインストール自体は成功しているにもかかわらず、続く sudo once background install の段階で sudo: once: command not found が発生することが報告されました。インストール完了後に手動で once を実行すると動作するという事実から、原因が sudo の PATH 制限にあることが明確でした。
この問題は /usr/local/bin のような非標準のインストールディレクトリが secure_path に含まれていない環境で特に顕在化します。
技術的な変更
ONCE_BIN 変数を導入し、once バイナリの絶対パスを保持することで、sudo 経由の呼び出しを含む全ての実行箇所をPATH解決に依存しない形に統一しました。
install_once() 関数では、once が既にインストール済みの場合は command -v once の出力、新規インストールの場合は ${INSTALL_DIR}/once を ONCE_BIN に格納するよう変更されました。
変更前:
if command -v once >/dev/null 2>&1; then
echo "once is already installed at $(command -v once)"
return
fi
# ...
echo "Installed once to ${INSTALL_DIR}/once"
echo "Installing background service..."
if is_root; then
once background install
else
sudo once background install
fi
変更後:
if command -v once >/dev/null 2>&1; then
ONCE_BIN=$(command -v once)
echo "once is already installed at ${ONCE_BIN}"
return
fi
# ...
ONCE_BIN="${INSTALL_DIR}/once"
echo "Installed once to ${ONCE_BIN}"
echo "Installing background service..."
if is_root; then
"${ONCE_BIN}" background install
else
sudo "${ONCE_BIN}" background install
fi
ONCE_BIN への代入は2箇所に分かれています。既存インストールのパスは command -v once で取得するため、/usr/local/bin 以外の場所にインストールされていた場合でも正しく追跡できます。この変更は run_once() 関数内の呼び出しにも波及し、exec once・exec sudo once・sg docker -c "once ..." のすべてが ${ONCE_BIN} を使った絶対パス指定に統一されています。
設計判断
ONCE_BIN をスクリプト全体で共有するグローバル変数として宣言する方式が採用されました。
install_once() で設定した値を run_once() でも参照する必要があるため、変数のスコープはスクリプトトップレベルに置かれています。空文字列で初期化しておくことで、変数が未設定のまま参照される状態を防いでいます。また command -v once を使った既存インストールのパス取得は、非標準ロケーションへのインストールを考慮した堅牢な判定方法であり、which コマンドへの依存を避ける慣用的なシェルスクリプトの書き方に沿っています。
sudo "${ONCE_BIN}" のようにダブルクォートで変数を囲んでいる点も、スペースを含むパスへの対応として適切です。
まとめ
ONCE_BIN という単一変数の導入により、インストール済みか否か・標準パスか否かを問わず、スクリプト全体でバイナリの絶対パスが一貫して使われるようになりました。sudo のPATH制限という環境依存の問題を、シェルスクリプトの慣用的なパターンで根本から解消した修正です。