web-dev-qa-db-ja.com

この「at」コマンドが標準出力に出力されないのはなぜですか?

私は比較的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標準出力と異なりますか?

15
Andrew

atは、ログインしているユーザーセッションのコンテキストではコマンドを実行しないためです。これは、コマンドを任意の時間に実行するようにスケジュールしてからログアウトすると、システムが指定した時間にコマンドを実行するようになるという考え方です。

at(1)のマニュアルページには、特に(私の強調)と書かれています。

ユーザーはメールで送信されます標準エラーおよびコマンドからの標準出力(ある場合)。メールは、コマンド/ usr/sbin/sendmailを使用して送信されます。

したがって、ローカルのメールスプールを確認するか、失敗するとローカルシステムのメールログを確認する必要があります。/var/spool/mail/$ USERは、おそらく開始するのに適しています。

また、「開始」と「終了」は外部スクリプトに由来し、それ自体はatとはまったく関係がないことに注意してください。それらを取り除いたり、atを呼び出したりすると、基本的に同じ結果が得られます。

19
a CVn

@MichaelKjörlingが説明したように、atジョブによって生成された出力はすべてキャプチャされ、電子メールで送信されます。実行中の MTA-Mail Transfer Agent がボックスにない場合は、メールが乱暴になっている可能性があり、atがこれを試みていることさえわかりません。

MTAはsendmailpostfixなどのプログラムで、適切な宛先にメールを「配信」できます。この場合、ローカルシステムのメールキュー(/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

これはメールキューの「受信トレイ」にあります。

ss of mutt's inbox

このメールをチェックしてみましょう:

ss of mutt's msg

そしてそれはうまくいった。

8
slm

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」がターミナルに表示されます...

6
AAAfarmclub

上記の答えはそれを行うための標準的な/「正しい」方法です。

より「エンドユーザー」の観点からより簡単な別のアプローチは、スケジュールされたタスクまたはバックグラウンドタスクがその出力を「ログ」ファイルに書き込むようにすることです。ファイルはシステムのどこにあってもかまいませんが、タスクが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_runatコマンドの時間が少し先になることを確認してから、ターミナルから実行しました。次に、実行されるまで待機して、$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>の代わりに使用して、ログファイルに出力を追加しました。アプリケーションに最適な方を使用してください。

2
Joe