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


12

Ubuntuサーバー16.04を使用atし、現在のセッションでユーティリティを使用し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を使用しています。


2
キルフラグがGNUスタイルであり、再配置できるため、「キルザウェンチャー」のように聞こえないことを願っています。
NH。

回答:


6

「こんにちは」ストリームは、プロンプトではstdinなく(で)印刷されます。stdout

いいえ、それはだない「あなたに印刷しますstdin」。

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


おそらく、次のような先頭の改行印刷したいでしょう(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前に1行だけを残します。SIGWINCHは、WINdowサイズが変更されると自動的に送信され、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両方のシステムで有効になって、それだけでバッシュ4.4システム(アーチの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を開いてください。コマンドの終了後、ターミナルを開いたままにするオプションを使用します。


デイビッドに心から感謝します。これは、私が探しているものに関して本当に近いものです。次のコマンドをアップグレードしてEnter、エコーが表示された直後にキーを押すイベントをエミュレートする方法はありますか?コンソールのプライマリプロンプトに自動的に戻りますか?(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
アークティクーリング

@Arcticoolingは:kill -WINCH $$ ないターミナルで実行中のシェルのプロンプトを更新します。それがそれを使用する全体のポイントでした。Enterキーを押すと、部分的に入力したコマンドが送信されますが、WINCHは送信しません。何も入力していない場合は、空のプロンプトが表示されます。
ピーターコーデス

1
rm -rf ~/some/directory入力し始めた場合、間違った時間にEnterを実行する可能性がありますrm -rf ~/。(安全性のヒント:パスの入力を終了してから control-aに変更lsrm -rf、に変更してください。いつでも太い指で入力しても、1日が台無しになりません。)
ピーターコーデス

有線で実行(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)し、エコーが表示された後、空のプロンプトが表示されました。ヒットした後Enter、プライマリプロンプトに戻りました...誤解して申し訳ありません。
アークティクーリング

@Arcticooling:KonsoleターミナルエミュレーターでArch LinuxのBash 4.4を使用しています。私は私のコマンドは、少なくとものbashの他のバージョンに移植できることを望んだが、多分:(うん、ただの内側バッシュ4.3でテストされていないscreen古いUbuntuシステム上のセッション(およびちょうどSSHを介して)、そして私はあなたが記述振る舞いを得ました。
ピーターコーデス

13

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

あなたの例では、 "some command"(下の例では "echo hi"を選択しました)を実行するために、enter(今)を押してから1分後に、<timespec>使用する予定ですnow + 1 minute。そのため、必要な結果をワンライナーソリューションで取得するには、以下のコマンドを使用してください。

echo 'echo hi' | at now + 1 minute

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

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

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

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

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

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


2
atデフォルトではメールを介して出力を送信しますが、これは正しく機能するように設定する必要があります。
サイモンリヒター

私は今、答えに100名の報奨金を提供しています。以下の賞金メッセージを読んで、at <timespec>使用したフラグとUbuntu 16.04 xenialに適しているかどうかを詳しく説明してください。
アークティクーリング

わかりました、答えの詳細レベルを上げて、より教訓的になりました。一部の人にとっては少々長引くように聞こえるかもしれませんが、動作する例とその動作方法を明確に引用しているので、疑いの余地はないと思います。
マルセロ

7

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

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

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


このメソッドには小さな問題があります--- "hi"ストリームは(通常の)のように私のプロンプトではstdinなくstdoutecho)に表示されます。
アークティクーリング

1
あなたはプロンプトや他のコマンドの出力を使用して、端末ミックスアップで出力したくない場合は、どこかにリダイレクトする必要があります
PiedPiper

このリダイレクトは@PiedPiperに失敗しました(sleep 10s; echo 'hi') & 1>。これについてもっと読みます。
アークティクーリング

2
ドキュメントを読むことは常に良いアイデアです:)
PiedPiper

1
@Arcticooling stdinand の意味について混乱しているようですstdout。端末のどこに表示されるかには関係ありません。代わりに、特定のプロセス(基本的にはプログラム)に関してそれらを解釈する必要があります。プロセスの標準入力( "stdin")はプロセスがデータを読み取ることができるソースであり、プロセスの標準出力( "stdout")はデータを書き込むことができる宛先です。これらのソースと宛先は、他のプログラム、ファイル、またはターミナル自体です(入力したものはstdinに送られ、stdoutに送られたものはすべて表示されます)。
デビッドZ

3

あなたはの出力をパイプしているので、それが失敗したecho "hi"だけであるhiat、しかしatそれの入力はデフォルトのシステムシェル(通常はbashが、時にはシステムに応じて、別の何か)で実行することができることを期待しています。

この:

at 1m << EOF
echo "hi"
EOF

あなたがしようとしているように見えるものを達成します。'here document'と呼ばれるシェル構造を使用します。これは一般に、このタイプのことを行うために受け入れられている方法です(echoコマンドを使用するよりも複数行を処理し、必要な新しいファイルを作成する必要がないため)cat)、およびecho

echo 'echo "hi"' | at 1m

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


何らかの理由で、あなたが与えた両方の例は私にエラーを与えますsyntax error. Last token seen: m Garbled time 。理由はわかりません。Ubuntu 16.04、Bash 4.0を使用しています。たぶん、あなたは別のシステムでそれをしました。atさらに引数を指定せずに入力しても、同じエラーが発生します。詳細データはこちら
アークティクーリング

1
at 1mposixと互換性がある場合は動作しませんat。コマンドは次のようにする必要がありますat now + 1 minute
PiedPiper

@PiedPiperは正しいです。1mはのPOSIX準拠バージョンと互換性がありませんat。その構文を受け入れるバージョンがあると仮定していました。
オースティンヘメルガーン

@PiedPiper at 1mはPOSIX ではありませんが、POSIX互換の実装atは自由に解釈できます。エラーを返すことや1か月前atを意味することを意味するものとして解釈する実装の準拠性を低下させることはありません。IOW、POSIXではないコードです。now + 1 minuteat 1m
ステファンシャゼル

2

@Peter Cordesの回答とこの回答を組み合わせる /programming/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;
}

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

(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を使用すると、私にとっては問題なく動作します。


1

上記の回答に基づいて、次のように埋め込みコマンドに出力を端末に送信させることができます。

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

このttyコマンドは、現在の端末のデバイスパスを返し、それを$(...)サブシェルでbashに実行させ、killコマンドは現在のプロセスにシグナルを送信し、bashに$ PS1プロンプトを再印刷させます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.