このスクリプトは、cron から実行すると失敗するのに、手動で実行すると機能するのはなぜですか?

このスクリプトは、cron から実行すると失敗するのに、手動で実行すると機能するのはなぜですか?

比較的単純な bash スクリプトがあり、直接呼び出すと正常に動作しますが、cron で実行すると失敗します。なぜ失敗するのでしょうか。また、cron 経由で動作させるにはどうすればよいのでしょうか。

#!/bin/bash
apt-get update -y
apt-get upgrade -y
apt-get install boinc-client -y

cron が実行を試みた後、手動で呼び出すと次のエラーが発生します。

dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.

ただし、最初に手動で実行する限りは、問題なく動作します。

答え1

この種の質問に対する通常の答えは、cron ジョブは非対話型の非ログイン シェルで実行されるため、ほとんどのシェル スタートアップ ファイル (システム全体のファイル/etcとホーム ディレクトリ内の個人用ドット ファイルの両方) はソース化 (読み取りおよび実行) されない、というものです。これは、ほとんどのシェル スタートアップ ファイルがログイン シェル (コンピューターにログインしたときに最初に表示されるシェル) または対話型シェル (ユーザーがターミナルを介して対話するため、ターミナル、ssh セッション、またはターミナル エミュレーターに接続されているシェル) に適用されるためです。

したがって、、、、またはなどの場所PATHで通常行われる環境設定 (変更を含む)に実際に依存するコマンドを cron ジョブに配置すると、その設定は cron ジョブでは行われません。cron ファイル形式ではジョブの環境変数を指定できるため、またはを指定して、ソースとなるシェル起動スクリプトを指すようにすることができます。マニュアル ページの「呼び出し」セクションを参照してください。/etc/profile/etc/bashrc~/.profile~/.bashrcBASH_ENVENVbash(1)

答え2

これは回答として適格ではありませんが、コメントできません。提案:

  1. 次のコードを bash スクリプトの先頭に追加します。メール出力に記録される最後の行が、失敗したコマンドになります。

    set -x
    set -e
    
    • postfixsendmail があることを確認します (またはなどの提供パッケージをインストールしますesmtp)
    • メールリーダーをインストールする(推奨mutt
    • メールが確実に届くようにする
      • postfix経由(インストーラーによって自動的に実行される可能性があります):root: my-user-nameまたは/etc/aliases/etc/postfix/aliases
      • cron経由:適切なファイルMAILTO="my-user-name"に追加crontab
  2. スクリプトが別の環境で実行されることを確認します。apt-get へのフルパスを指定し (apt-get が見つかったことがわかっているため、おそらく原因ではありません)、X 外部のコンソール (ターミナルではない) で実行します (一部の dpkg configure スクリプトでは X セッションが必要です)。

    • 絶対パスを使用するようにスクリプトを変更します/usr/bin/apt-get update -y(正しいパスに置き換えます)。
    • を押してコンソールに切り替えるctrl-alt-f1
    • ルートユーザーに切り替えます:sudo -i
    • 環境なしで非ログインシェルを起動します: env -i /bin/bash --noprofile --norc(正しいパスに置き換えてください)
    • スクリプトを実行します:/my/full/path/to/cronscript動作しますか?
  3. スクリプトに権限がありますか? システムの crontab を使用していますか? (繰り返しますが、おそらく原因ではありません)

    • システムの crontab を使用していると述べているため、これをスキップします。
  4. apt-get にはセッション サポート (consolekit または systemd) が必要ですか。ただし、これは単なる推測です。

    • 役に立つほどの知識はありません。

答え3

何が起こっているのかほとんど理解せずに、なんとか解決できました。root crontab から実行していたにもかかわらず、apt-get コマンドの前に sudo が必要であることが判明しました。論理的には、スクリプトがすでに「root として」実行されていたため、これは必要ないと思っていましたが、sudo を追加すると、すべてが期待どおりに機能しました。

関連情報