Bash機能を実行するために "at"コマンドを使用できますか?

Bash機能を実行するために "at"コマンドを使用できますか?

スケジュールされた時間にBash機能を実行したいです。正しいツールはatコマンドだと思います。

しかし、うまくいかないようです。

function stupid () {
    date
}

export -f stupid

cat << EOM | at now + 1 minute
stupid
EOM

しばらく待ってからメールを確認しましたが、次のエラーが表示されました。

sh: line 41: syntax error near unexpected token `=\(\)\ {\ \ date"
"}'
sh: line 41: `"}; export BASH_FUNC_stupid()'

特に関数が機能していることを知っているので、ここで何が間違っているのかわかりません。

$ stupid
Fri May 29 21:05:38 UTC 2015

エラーを見ると、関数の実行に間違ったシェルが使用されているようですが(sh代わりにbash)、確認してみると を指すように$SHELL見え、/bin/bashマニュアルページに次のようにat示されています。

$ echo $SHELL
/bin/bash
$ man at

    ...

    SHELL   The value of the SHELL environment variable at the time
           of at invocation will determine which shell is used  to
           execute  the at job commands.

したがって、Bashは私の機能を実行するシェルでなければなりません。

どうなりますか?私のBash機能を一緒に実行する方法はありますかat

答え1

Bash機能は環境を介してエクスポートされます。このatコマンドは、環境を再現するシェルコードを生成し、呼び出しプロセスの環境、umask、および現在のディレクトリをスクリプトで使用できるようにします。 at ジョブで実行されるスクリプトは次のとおりです。

#!/bin/bash
umask 022
cd /home/nick
PATH=/usr/local/bin:/usr/bin:/bin; export PATH
HOME=/home/nick; export HOME
stupid

()以前のバージョンのbashでは、関数名と関数を定義したコードで始まり、設定された値を含む変数に関数をエクスポートしました。

stupid="() {
    date
}"; export stupid

これにより、多くのシナリオがセキュリティの脆弱性に対して脆弱になります。シェルショックバグ(で見つかりましたスティーブン・チャジェラス)を使用すると、誰でも任意の名前で環境変数の内容を注入して、bashスクリプトから任意のコードを実行できます。 Shellshockの修正を含むbashバージョンは異なるアプローチを使用します。名前に環境変数で見つからない文字を含む変数に関数定義を格納し、シェルはそれを割り当てとして解析しません。

BASH_FUNC_stupid%%="() {
    date
}"; export stupid

これは有効な sh 構文ではないため、%bash でも at 操作は関数を使用するかどうかに関係なく失敗します。これat の Debian バージョンは多くのLinuxディストリビューションで使用されています。変更バージョン3.16では、シェルスクリプトに有効な名前を持つ変数のみがエクスポートされます。したがって、atの最新バージョンはShellshockの後ろからbashを介して機能をエクスポートしませんが、古いバージョンは失敗します。

Shellshock 以前のバージョンの bash を使用しても、エクスポートされた機能は、at ジョブ自体ではなく at ジョブで開始された bash スクリプト内でのみ機能します。 atジョブ自体内では、bashによって実行されてもstupidbashは起動時にのみ機能を取得する別の環境変数です。

関数をatジョブとしてエクスポートするには(bashまたはバージョンに関係なく)、その関数をファイルに入れ、ジョブからファイルを取得するか、ジョブに直接含めます。定義されたすべての関数を読み取り可能な形式で印刷するには、を使用しますdeclare -f

{ declare -f; cat << EOM; } | at now + 1 minute
stupid
EOM

答え2

at/bin/sh代わりに使用するように設計されているため、/bin/bash使用可能なコード序文が前に追加されます。何かを接続して使用するには、次の簡単な機能を使用してください。at -c {jobnumber}bash

at_with_bash_alias_and_functions(){
  ( 
    echo "exec /bin/bash <<END"
    alias
    typeset -f
    cat
    echo END
  ) | sed 's/\$/\\$/g' | at "$@"
}

エイリアスと関数が存在するかどうかを表示します。

at_with_bash_alias_and_functions now <<< "alias;typeset -f"

制限事項:インライン処理はシェル置換のため、構文が失われる可能性があり、構文を検証する代わりに.usesatのように動作します。exec catexec bash

答え3

まあ、あなたはすでに郵便を受け取ることになることを知っています。クールだから君は絶対にできるbashメールが届いたときに実行される関数です。

ソースman bash:

  • $MAILPATH

    • メールを確認するファイル名をコロンで区切ったリストです。メッセージが特定のファイルに到着したときに印刷されるメッセージは、ファイル名とメッセージを区切る区切り文字を使用して指定できます。。メッセージテキストに使用されている場合は、$_現在のメールファイルの名前に展開されます。例:

      MAILPATH='/var/mail/bfox?"You have mail":~/shell-mail?"$_ has mail!"'
      
    • bashこの変数にはデフォルト値が指定されていますが、使用されるユーザーメールファイルの場所はシステムによって異なります。(たとえば、/var/mail/$USER

ところで、$_いいえただこの文脈では、可能な拡張 - コマンドの置換を含め、ほぼすべてを拡張できます。実は必ずしも必要はありませんが印刷何もない。ファイルに必ずしも以下を含める必要はありません。郵便$MAILCHECKまたは - シェルは、1 秒あたりの確認結果ファイルが最後に表示されてから変更されたことを示すときに通知しようとします。

それにもかかわらず、シェルがこれを処理する方法は$MAILxxxx通常、プロンプトによって異なります。つまり、$MAILCHECK値に関係なくタイムリーに新しいプロンプトを取得しないと、通知が表示されません。次のプロンプトを通知するためにトリガーするまで通知を受け取ります。これはよくわかりませんが、set -b影響を与える可能性があります。

とにかく、このようなことをする方法はいくつかあります。おそらく最も確実な方法は、信号を使用してタスクatをスケジュールすることです。たとえば、次のようになります。

echo kill -USR1 "$$" | at now + 1 minute
trap some_func USR1

何が起こっているのか確認してください。

関連情報