( ) cronjob からスクリプトを呼び出すと、root
「ipset が見つかりません」というメッセージが表示されて失敗します。問題のあるスクリプト行は次のとおりです。
for i in $(cat /etc/cn.zone); do ipset -A china $i; done
スクリプト内の数行前でこのコマンドが呼び出されます:
ipset -N china hash:net
したがって、問題の ipset は実際に作成されました。
このスクリプトをルートのホーム ディレクトリから実行すると、問題なく実行されます。
エラーの原因は何だと思いますか?
答え1
スクリプトを cron ジョブとして実行すると、環境変数が認識されません。
( ) cronjob からスクリプトを呼び出す
root
と、「ipset が見つかりません」というメッセージが表示されて失敗します…
このスクリプトを Bash スクリプトとして実行していますか? これは最近のほとんどのシェル スクリプトと同じですか?
もしそうなら、スクリプトの最初の行を
#!/bin/bash
これに対して:
#!/bin/bash -l
を追加すると、-l
Bash はログイン シェルとして呼び出されたかのように実行されます。また、その cron ジョブで Bash スクリプトがログイン シェル経由で実行されると、通常ログイン シェル経由で設定されるすべての環境変数やその他の項目がその Bash スクリプトで使用できるようになり、ipset
期待どおりに実行できるようになります。
which
もう一つのトリックは、次のように Bash 変数内で使用することです。明らかにこれを使用している$(cat /etc/cn.zone)
ので、メカニズムは似ています。
$(which ipset)
スクリプト内の行を次のように変更します。
for i in $(cat /etc/cn.zone); do $(which ipset) -A china $i; done
これは、 を使用してwhich
、これを実行しているシステム上の への完全なパスipset
( など/sbin/ipset
) をスクリプトに指定します。 次に、 を介してそれを解析された変数として設定すると、$()
スクリプト自体がそれを実行できるようになります。
ipset
ただし、スクリプトの他の場所で使用する場合、このwhich
方法を使用する場合は、スクリプトをリファクタリングして、ipset
スクリプトの先頭近くで次のように変数として設定することをお勧めします。
ipset_bin=$(which ipset);
そして、次のようにコマンドを呼び出します。
$ipset_bin -N china hash:net
この:
for i in $(cat /etc/cn.zone); do $ipset_bin -A china $i; done
答え2
シェルは、環境によって設定されているが、同じ環境を共有していない をipset
調べることで、実行可能ファイルがどこにあるかを認識します。PATH
cron
これを (またはスクリプトの) の先頭に追加すると、crontab
期待どおりにコマンドがどこにあるかがわかります。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin