私は比較的Linuxの初心者です。 at
を使用せずに、後で開始するタスクをスケジュールできるように、sleep
の使用方法を学習しようとしています。 この前の質問 を参考にしてきました。
私の質問は、私が作成した次のサンプルbashスクリプトで、なぜ "Running"は決して-私の知る限り-印刷されるのですか?標準出力(つまり、私のbashコンソール)に?
#!/bin/bash
echo "Started"
at now + 1 minutes <<EOF
echo "Running"
EOF
echo "Finished"
私が見る唯一の出力は、例えば:
Started warning: commands will be executed using /bin/sh job 3 at Fri Jul 12 17:31:00 2013 Finished
私の質問に対する答えは警告にありますか?もしそうなら、/bin/sh
標準出力と異なりますか?
at
は、ログインしているユーザーセッションのコンテキストではコマンドを実行しないためです。これは、コマンドを任意の時間に実行するようにスケジュールしてからログアウトすると、システムが指定した時間にコマンドを実行するようになるという考え方です。
at(1)
のマニュアルページには、特に(私の強調)と書かれています。
ユーザーはメールで送信されます標準エラーおよびコマンドからの標準出力(ある場合)。メールは、コマンド/ usr/sbin/sendmailを使用して送信されます。
したがって、ローカルのメールスプールを確認するか、失敗するとローカルシステムのメールログを確認する必要があります。/var/spool/mail/$ USERは、おそらく開始するのに適しています。
また、「開始」と「終了」は外部スクリプトに由来し、それ自体はat
とはまったく関係がないことに注意してください。それらを取り除いたり、at
を呼び出したりすると、基本的に同じ結果が得られます。
@MichaelKjörlingが説明したように、at
ジョブによって生成された出力はすべてキャプチャされ、電子メールで送信されます。実行中の MTA-Mail Transfer Agent がボックスにない場合は、メールが乱暴になっている可能性があり、at
がこれを試みていることさえわかりません。
MTAはsendmail
やpostfix
などのプログラムで、適切な宛先にメールを「配信」できます。この場合、ローカルシステムのメールキュー(/var/spool/mail
ディレクトリの下のファイル)に配信されます。システム上の各ユーザーは、このディレクトリにキューを持つことができます。
私のFedoraシステムでsendmail
を起動すると、ローカルメール配信が発生する可能性があります。私は通常それを持っています。
$ Sudo service start sendmail
これで、ユーザーアカウントsaml
のメールキューが空であることがわかります。
$ ll /var/spool/mail/|grep saml
-rw-rw----. 1 saml mail 0 Jul 12 19:33 saml
そこで、at
ジョブを実行します。
$ at now + 1 minutes <<EOF
echo "Running"
EOF
job 96 at Fri Jul 12 19:38:00 2013
ジョブがatq
での実行を待機していることがわかります。
$ atq
96 Fri Jul 12 19:38:00 2013 a saml
数分後にもう一度実行すると、at
ジョブが完了したことがわかります。
$ atq
$
ちなみに、MTAを実行すると、ターミナルに次のメッセージが表示されます。
/ var/spool/mail/samlに新着メールがあります
確認しましょう:
$ ll /var/spool/mail/|grep saml
-rw-rw----. 1 saml mail 651 Jul 12 19:38 saml
メールが届いたので、mutt
を使用して確認してみましょう。
$ mutt -f /var/spool/mail/saml
これはメールキューの「受信トレイ」にあります。
このメールをチェックしてみましょう:
そしてそれはうまくいった。
Debian 8.1(jessie)を実行しています
ttyを使用して、「at」出力を端末に送ることができます。
$ tty
/dev/pts/1
$ at now + 1 min
warning: commands will be executed using /bin/sh
at> echo 'ZZZZZ' > /dev/pts/1
at> <EOT>
1分後、「ZZZZZ」がターミナルに表示されます...
上記の答えはそれを行うための標準的な/「正しい」方法です。
より「エンドユーザー」の観点からより簡単な別のアプローチは、スケジュールされたタスクまたはバックグラウンドタスクがその出力を「ログ」ファイルに書き込むようにすることです。ファイルはシステムのどこにあってもかまいませんが、タスクがrootとして実行されている場合(cron
などから)、/var/log
のどこかに置くとよいでしょう。
私は/var/log/maint
ディレクトリを作成し、誰でも読み取り可能にしました。その下に「backup」という読み取り可能なファイルがあり、バックアップスクリプトからの出力をログに記録しています。
自分のディレクトリを作成して、ファイルがシステムによって生成されたものと混同されないようにしました。
そこにものを置くには(bashで):
BACKUP="/var/log/maint/backup"
echo "my message" >> "${BACKUP}"
>>
を指定すると、メッセージが毎回上書きされるのではなく、ファイルに追加されます。
スクリプトに大量の出力がある場合は、出力にスクリプトまたは関数を使用して、すべてが同じように実行されるようにします。以下は私の現在の(overkillバージョン)です(ターミナルからスクリプトを実行していて、デバッグの目的で何が行われているのかを確認したい場合のためにVERBOSEが用意されています)。
#!/bin/bash
## backup_logger
## backup system logging module
## Copyleft 01/20/2013 JPmicrosystems
## Usage is ${SCRIPT_NAME} [-v] [<caller> <log message text>]
## If present, -v says log to console as well as to the log file
## <caller> is the name of the calling script
## If <caller> <log message text> is not present, write a blank line to the log
## Must be placed in path, like ~/bin
## If log is owned by root or another user, then this must run as root ...
## If not, it just aborts
##source "/home/bigbird/bin/bash_trace" ## debug
SCRIPT_NAME="$(basename $0)"
USAGE="Usage is ${SCRIPT_NAME} [-v] [<caller> <log message text>]"
SYSLOGDIR='/var/log/maint'
SYSLOGFILE="${SYSLOGDIR}/backup.log"
LOGGING=1
VERBOSE=0
if [ "${1}" == "-v" ]
then
VERBOSE=1
shift
fi
##LOGGING=0 ## debug
##VERBOSE=1 ## debug
## Only zero or two parameters allowed - <caller> <log message text>
RC=0
if [ "$#" -eq 1 ] || [ "$#" -gt 2 ]
then
echo "${USAGE}"
RC=1
else
if [ ! -w "${SYSLOGFILE}" ]
then
touch "${SYSLOGFILE}"
if [ $? -ne 0 ]
then
echo -e "$(date) ${1} ${2}"
echo "${SCRIPT_NAME} Can't write to log file [${SYSLOGFILE}]"
RC=1
exit ${RC}
fi
fi
if [ -n "${1}" ]
then
(( LOGGING )) && echo -e "$(date) ${1} ${2}" >> "${SYSLOGFILE}"
(( VERBOSE )) && echo -e "$(date) ${1} ${2}"
else
(( LOGGING )) && echo "" >> "${SYSLOGFILE}"
(( VERBOSE )) && echo ""
fi
fi
exit $RC
編集:ユーザーファイルに書き込む単純なat
の例
これを永遠に使用したことがないので、いくつかの簡単なスクリプトでそれを理解しました。
最初のスクリプトは、at
を使用してイベントをスケジュールするだけです。コマンド自体は単に端末に入力することもできますが、私は怠惰です-特に、コマンド履歴をだまさずにテストしながら複数回実行する必要がある場合。
#!/bin/bash
## mytest_at_run
## Schedule a script to run in the immediate future
echo "/home/bigbird/bin/mytest_at_script" | at 00:56
2番目のスクリプトは、実行がスケジュールされているスクリプトです
#!/bin/bash
## mytest_at_script
## The script to be run later
echo "$(date) - is when this ran" >> /home/bigbird/log/at.log
テキストエディタで両方のスクリプトを作成して保存し、chmod 700 script-file-name
を使用してそれぞれを実行可能にしました。便宜上、両方を$HOME/bin
ディレクトリに配置しましたが、ユーザーがフルアクセスできる場所であればどこにでも配置できます。テスト専用のスクリプトには700
を使用していますが、シングルユーザーシステムでは755
にすることもできます。
/home/bigbird/log
からの出力を保存するためのmytest_at_script
というディレクトリがすでにあります。これは、ユーザーが完全にアクセスできる場所であればどこでも可能です。スクリプトを実行する前に存在することを確認するか、スクリプトで作成してください。
それを実行するために、mytest_at_run
のat
コマンドの時間が少し先になることを確認してから、ターミナルから実行しました。次に、実行されるまで待機して、$HOME/log/at.log
の内容を調べました。
bigbird@sananda:~/bin$ cat ~/log/at.log
Fri Sep 14 00:52:18 EDT 2018 - is when this ran
Fri Sep 14 00:56:00 EDT 2018 - is when this ran
bigbird@sananda:~/bin$
いくつかのメモ:
ユーザーからat
を実行していますが、PATH
やホームディレクトリなどの環境を認識していないため、想定していません。 cron
ジョブと同じように、フルパスを使用します。そして、それをcron
ジョブにしたい場合は、実行するために何も変更する必要はありません。
>>
のmytest_at_script
を>
の代わりに使用して、ログファイルに出力を追加しました。アプリケーションに最適な方を使用してください。