web-dev-qa-db-ja.com

しばらくしてから何かを実行してください(結果をコンソールに表示することもできます)

私はUbuntuサーバー16.04を使用しており、現在のセッションでユーティリティatを使用して、特定の日付と時刻を指定せずに、1分後(たとえば、echo)に何かをしたいと思っています。現在時刻から1分進んでいます。

これは失敗しました:

echo 'hi' | at 1m

atよりもsleepを選択する理由は、スリープが現在のセッションをハンディキャップしているため、ほとんどの場合作業しているセッションよりも、別のセッションでコマンドを遅延させるのに適しています。 AFAIR、atはこのように動作せず、セッションをハンディキャップしません。

Update_1

Pied Piperの答えにより、私は試してみました:

(sleep 1m; echo 'hi')  &

この方法に問題があります。「hi」ストリームがプライマリプロンプト内に印刷され、空のセカンダリプロンプト(_)それを含むプライマリプロンプトのすぐ下、以下を参照してください。

USER@:~# (sleep 1m; echo 'hi')  &
[1] 22731
USER@:~# hi
^C
[1]+  Done

Update_2

ピーター・コーデの答えで私は試しました:

(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)

これはBash 4.4では正しく機能しますが、一部の古いバージョンでは機能しないようです(回答のコメントを参照)。私は自分の環境でBash 4.3を個人的に使用しています。

12
Arcticooling

「hi」ストリームは私のプロンプト(stdin)に出力され、stdoutには出力されません

いいえ、それはではありませんstdinに出力されます」。

Returnキーを押した場合、hiをコマンドとして実行しようとはしません。カーソルがプロンプトの後にあるときに、背景のechohiを印刷しただけです。


おそらく、(sleep 1m && echo -e '\nhi' &)のように、先頭の改行を印刷したい場合があります。 (必要に応じて、シェルのechoを調整します。または、移植性のためにprintfを使用します。)

サブシェル内に&を配置してバックグラウンドジョブを「否認」するので、[1]+ Doneの「ノイズ」も回避できます。コマンド間に&&がある場合、&は複合コマンドチェーン全体に適用されるため、sleepが終了するのを待たずに、すぐにシェルプロンプトに戻ります。 (sleep 1; echo ... &)

これが何が起こるかです(1秒の遅延で):

peter@volta:~$ (sleep 1 && echo -e '\nhi' &)
peter@volta:~$ 
hi
       # cursor is at the start of this empty line.

Bashはechoが何かを印刷したことを認識していないため、プロンプトを再印刷したり、画面をクリーンアップしたりする必要があることを認識していません。 control-Lを使用して手動で行うことができます。

bashを取得して、echoが終了した後にプロンプ​​トを再出力するシェル関数を作成できますecho "$PS1"を実行するだけでは、入力済みの文字は再現されません。 kill -WINCH $$システムでbashを取得すると、画面をクリアせずにプロンプ​​ト行を再印刷し、hiを行に残しますプロンプトの前に単独で。 WINdowサイズが変化すると、SIGWINCHが自動的に送信されます。これに対するbashの応答は、私たちが望むことを実行します。

他のシェルでも動作するかもしれませんが、私はこれを100%移植性のある/ POSIXにするつもりはありません。 (残念ながら、これはbash4.3ではなくbash4.4でのみ機能するか、知らない設定に依存します

  # bash4.4
peter@volta:~$ (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
peter@volta:~$ ljlksjksajflasdf dfas      # typed in 2 seconds
hi
peter@volta:~$ ljlksjksajflasdf dfas      # reprinted by Bash because of `kill -WINCH`

これは、スリープ引数とメッセージを受け取るシェル関数で簡単にラップできます。

bash 4.3はSIGWINCHの後にプロンプ​​トを再出力しないため、これはそこで機能しません。両方のシステムでshopt -s checkwinsizeを有効にしていますが、Bash 4.4システム(Arch Linux)でのみ機能します。

機能しない場合は、(sleep 2 && echo -e '\nhi' && echo "$PS1" &)を試してください。これは、コマンドラインが空の場合に機能します。 (また、Prompt_COMMANDが設定されている可能性も無視します。)


タイマーが作動したときに、ターミナル出力を後でターミナルで実行する可能性のあるものと混合するための本当にクリーンな方法はありません。 lessで何かをスクロールしている最中は、見落としがちです。

インタラクティブな結果が得られるものを探している場合は、オーディオファイルを再生することをお勧めします。例えば mpv (MPlayer2の素敵なフォーク)のようなコマンドラインプレイヤーで。または、新しいウィンドウが開くようにビデオファイルを選択します。

(sleep 1 && mpv /f/share/music/.../foo.ogg </dev/null &>/dev/null &)

echoで新しいxterm/konsole/gnome-terminalを開いてください。コマンドの終了後もターミナルを開いたままにするオプションを使用します。

6
Peter Cordes

正しいatの使用法はat <timespec>です。ここで、<timespec>は時間指定です。 -fオプションを使用して、実行するコマンドを含むファイルを指定することもできます。 -fでリダイレクトを使用しない場合、atはstdin(標準入力)から実行するコマンドを読み取ります。

あなたの例では、「some command」を実行するには(以下の例では「some command」を「echo hi」に選択しました)、Enterキーを押した直後(今)、意図した<timespec>が使用されますnow + 1 minute。したがって、ワンライナーソリューションで必要な結果を得るには、以下のコマンドを使用してください。

echo 'echo hi' | at now + 1 minute

これは、1分後にecho hiコマンドを実行することが想定されています(実行されます)。ここでの問題は、echo hiコマンドがダミーのttyでatコマンドによって実行され、出力がユーザーのメールボックスに送信されることです(正しく構成されている場合-これには、 UNIXマシンでメールボックスを構成し、この質問の範囲の一部ではありません)。つまり、コマンドを発行したのと同じターミナルでecho hiの結果を直接見ることはできません。最も簡単な代替手段は、たとえば「次のようなファイル」にリダイレクトすることです。

echo 'echo hi > /tmp/at.out' | at now + 1 minute

上記の例では、「一部のファイル」は/tmp/at.outであり、予期される結果は、/ tmpの下のファイルat.outが1分後に作成され、テキスト「hi」を含むことです。

上記のnow + 1 minuteの例に加えて、複雑なものも含め、他の多くの時間指定を使用できます。 atコマンドは、以下の例のように人間が読めるものを解釈するのに十分スマートです。

now + 1 day13:25mid‐nightnoon、...

可能なバリエーションはかなり広範囲であり、日付、相対時間または絶対時間などが含まれる可能性があるため、可能な時間指定の詳細についてはatのmanページを参照してください。

13
Marcelo

サブシェルでsleepを実行します。

(sleep 60; echo -e '\nhi')  &

注:Linuxでは、秒単位で、または接尾辞s/m/h/d(秒、分、時間、日)を使用して、スリープの引数を指定できます。 BSDでは、引数は秒単位である必要があります

7
PiedPiper

echo "hi"の出力(hiatにパイプしているだけですが、atは、その入力がデフォルトで実行できると想定しているため、失敗しましたシステムシェル(通常はbashですが、システムによっては異なる場合があります)。

この:

at 1m << EOF
echo "hi"
EOF

あなたがしようとしているように見えることを達成します。これは「ヒアドキュメント」と呼ばれるシェル構造を使用します。これは、このタイプのことを行うために一般に受け入れられている方法です(echoコマンドを使用するよりも複数行を処理し、新しいファイルを作成する必要がないためです) cat)を使用する必要があるように、echoを使用して、やや複雑な同等のものに変換します。

echo 'echo "hi"' | at 1m

atは、atを使用して遅延されたコマンドとして端末に出力を送信するのではなく、sleepコマンドを呼び出したユーザーにコマンド出力をメールで送信することに注意してください。サブシェルで。特に、これは、システムのカスタマイズを行っていないか、ローカルのメールスプールを読み取るつもりでない限り、atを介して実行されたコマンドの出力を取得できないことを意味します。

3

@Peter Cordesの回答とこの回答を組み合わせる https://stackoverflow.com/questions/23125527/how-to-return-to-bash-Prompt-after-printing-output-from-backgrounded-function/23125687# 23125687

以下のコードは、私の答えを少し変更した、後者の回答からのものです。それをコンパイルしてファイルa.outを作成します(任意の名前に)

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        char *tty = "/dev/tty";
        if (argc > 1)
                tty = argv[1];
        int fd = open(tty, O_WRONLY);

        int i;
        char buf[] = "\n";
        for (i = 0; i < sizeof buf - 1; i++)
                if (ioctl(fd, TIOCSTI, &buf[i]))
                        perror("ioctl");
        close(fd);
        return 0;
}

次に、以下のコマンドを実行します。 (私はdir/tmp /にa.outを置きます、あなたはあなたのものに変更する必要があるかもしれません)

(sleep 2 && echo -e '\nhi' && /tmp/a.out &)

または

(sleep 2 && echo -e '\nhi' && /tmp/a.out /proc/$$/fd/0 &)

ところで、kill -WINCH $$は、GentooのBash 4.3でうまく動作します。

2
Bruce

上記の答えに基づいて、次のように埋め込みコマンドで出力をターミナルに送信できます。

echo "echo hi >$(tty); kill -WINCH $$" | at now + 1 minute

ttyコマンドは、現在のターミナルのデバイスパスを返し、$(...)で囲みます。サブシェルでbashを実行します。killコマンドは、現在のプロセスにシグナルを送信し、 $ PS1プロンプトをbashに再印刷してもらいます。

1
user1404316