エレガントな方法で永遠に何もしない方法は?


82

に役立つ情報を生成するプログラムstdoutがありますが、からも読み取りますstdin。標準入力に何も提供せずに、標準出力をファイルにリダイレクトしたい。これまでのところ、とても良い:できること:

program > output

ttyでは何もしません。

ただし、問題はこれをバックグラウンドで実行することです。私が行った場合:

program > output &

プログラムは中断されます(「中断(tty入力)」)。

私が行った場合:

program < /dev/null > output &

EOFに達するため、プログラムはすぐに終了します。

私が必要なのはprogram、無期限に何もせず、読まない何かにパイプすることstdinです。次のアプローチが機能します。

while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &

しかし、これは非常にいものです。そこ持ち(言い換えために「無期限に、何もしない」ために、標準のUnixユーティリティを使用して、エレガントな方法であることをman true)。どうすればこれを達成できますか?(ここでの優雅さの主な基準:一時ファイルなし、ビジー待機または定期的なウェイクアップなし、エキゾチックなユーティリティなし、可能な限り短い。)


試してみてくださいsu -c 'program | output &' user。「サービス/デーモン」を処理するための許容可能な方法としてバックグラウンドジョブを作成することで、同様の質問をしようとしています。STDERRまた、リダイレクトしないとリダイレクトできないことに気付きましたSTDOUT。programAがprogramBに送信してSTDOUTからログファイルにSTDINリダイレクトSTDERRするソリューション:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
mbrownnyc

多分... su -c 'while true; do true; done | cat > ~/output &' user
mbrownnyc

それはどんなプログラムですか?
ジョアンポルテラ


作成したプログラムにスイッチを追加するだけではどうですか?また、標準入力を閉じ1<&-てプログラムを終了すると仮定しますか?
w00t

回答:


16

それらをサポートするシェル(ksh、zsh、bash4)ではprogramコプロセスとして開始できます

  • kshprogram > output |&
  • zshbashcoproc program > output

これはprogram、入力がからリダイレクトされるバックグラウンドで始まりpipeます。パイプのもう一方の端は、シェルに対して開いています。

そのアプローチの3つの利点

  • 追加のプロセスはありません
  • program死んだときにスクリプトを終了できます(waitそれを待つために使用します)
  • program終了します(eofシェルが終了すると、その標準入力になります)。

それはうまくいくようで、素晴らしいアイデアのようです!(公平を期すために、シェル機能ではなく、コマンドにパイプするものを要求しましたが、これはプレイ中のXYの問題でした。)@PTの代わりにこの答えを受け入れることを検討しています。
a3nm

1
@ a3nm tail -f /dev/nullは毎秒読み取りを行うため、理想的ではありません/dev/null(inotifyを使用したLinux上のGNU tailの現在のバージョンには実際にはバグがあります)。sleep infまたは、より移植性の高い同等物sleep 2147483647は、IMOを何もせずにそこに座っているコマンドのより良いアプローチです(またはのsleepようないくつかのシェルで構築されていることに注意してください)。ksh93mksh
ステファンシャゼル

78

私はあなたがよりエレガントになるとは思わない

tail -f /dev/null

既に提案していること(これが内部的にinotifyを使用していると仮定すると、ポーリングやウェイクアップはないはずなので、見た目がおかしい以外は十分です)。

無期限に実行され、stdoutを開いたままにしますが、stdoutに実際には何も書き込まず、stdinが閉じられても終了しないユーティリティが必要です。yes実際にstdoutに書き込むようなもの。 catそのstdinが閉じられると(またはリダイレクトされたものはすべて終了すると)終了します。うまくいくと思いますsleep 1000000000dが、tail明らかに優れています。私のDebianボックスには、tailfコマンドを少し短縮するものがあります。

別のタックを取って、プログラムを実行するのはどうscreenですか?


tail -f /dev/nullコマンドの使用法は意図した目的に非常によく一致するため、このアプローチが最も気に入っています。
jw013

2
strace tail -f /dev/nullそれからのようにtail使用さinotifyれ、ウェイクアップはのような愚かな場合に発生するようsudo touch /dev/nullです。より良い解決策がないように思われるのは悲しいことです...より良い解決策を実装するために使用する正しいシステムコールはどれだろうかと思います。
a3nm

5
@ a3nm syscallはになりますがpause、シェルインターフェイスに直接公開されません。
ジル

PT:私は知ってscreenいますが、これはテストのためにシェルスクリプトからプログラムの複数のオカレンスを実行するためscreenです。
a3nm

3
@sillyMunky愚かな猿、WaelJの答えは間違っています(無限のゼロを標準入力に送信します)。
PT

48

sleep infinity 私が知っている最も明確な解決策です。

あなたが使用することができるinfinityので、sleep浮動小数点数受け入れ*てもよい、小数進数無限大、またはNaNのに応じて、man strtod

*これはPOSIX標準の一部ではないため、ほどポータブルではありませんtail -f /dev/null。ただし、GNU coreutils(Linux)およびBSD(Macで使用)でサポートされています(明らかに、Macの新しいバージョンではサポートされていません—コメントを参照)。


ハハ、それは本当に素晴らしいアプローチです。:)
a3nm

@ a3nm:ありがとう:)BSDとMacsleep infinityでも動作するようです。
ザズ14

無限にスリープ状態のプロセスはどのようなリソースを使用しますか?ただのRAM?
CMCDragonkai

1
この回答は、sleep infinity最大24日間待機すると主張しています。誰が正しい?
nh2

1
@Zaz現在、この問題を詳細に調査しました。最初は正しかったことがわかりました!sleepユーティリティは、24日に限定されるものではありません。これは24日間スリープする最初のシステムコールであり、その後はさらにそのようなシステムコールを実行します。:ここで私のコメントを参照してくださいstackoverflow.com/questions/2935183/...
NH2

19
sleep 2147483647 | program > output &

はい、これ2^31-1は有限数であり、永久に実行されることはありませんが、スリープが最終的にタイムアウトになったときに$ 1000を差し上げます。(ヒント:私たちのうちの1人はそれまでに死んでしまいます。)

  • 一時ファイルなし; 小切手。
  • ビジー待機または定期的なウェイクアップなし。小切手
  • エキゾチックなユーティリティはありません。小切手。
  • できるだけ短くします。さて、それは短くなる可能性があります。

5
bash:sleep $((64#1 _____))| プログラム>出力&
ディエゴトーレスミラノ

それは68のために眠る、これは98件のために眠る世紀sleep 2147483647d...
AGC

9

次のようにして、まさにそれを行うバイナリを作成できます。

$ echo 'int main(){ pause(); }' > pause.c; make pause

5

「無期限に何もしない」ために、標準のUnixユーティリティ使用した別の提案次に示します

sh -c 'kill -STOP $$' | program > output

これにより、すぐに送信されるシェルが起動されSIGSTOP、プロセスが中断されます。これは、プログラムへの「入力」として使用されます。補数でSIGSTOPあるSIGCONTあなたはシェルがあなたができるPID 12345を持って知っている、すなわちあれば、kill -CONT 12345それを継続させるために。


2

Linuxでは、次のことができます。

read x < /dev/fd/1 | program > output

Linuxでは、/ dev / fd / x(xはパイプの書き込み側へのファイル記述子)を開くと、パイプの読み取り側が取得されるため、ここではプログラムのstdinと同じです。そのreadため、そのパイプに書き込むことができるのはそれ自体であり、read何も出力しないため、基本的には戻りません。

FreeBSDまたはSolarisでも動作しますが、別の理由があります。そこで、/ dev / fd / 1を開くと、fd 1で開くのと同じリソースが期待どおりに取得され、Linuxを除くほとんどのシステムがそうであるように、パイプの書き込みが終了します。ただし、FreeBSDおよびSolarisでは、パイプは双方向です。そのprogramため、stdinに書き込まない限り(アプリケーションは書き込みません)、readパイプのその方向からは何も読み取れません。

パイプが双方向ではないシステムではread、書き込み専用ファイル記述子から読み取ろうとすると、おそらくエラーで失敗します。また、すべてのシステムにがあるわけではないことに注意してください/dev/fd/x


非常に素晴らしい!実際、私のテストではxwith bash は必要ありません。さらにzshを使えば、できることはできますがread、動作します(理由はわかりません!)。これはLinux固有のトリックですか、それともすべての* nixシステムで動作しますか?
a3nm

@ a3nm、read単独で行う場合、stdinから読み取ります。そのため、端末の場合は、Enterキーを押すまで入力内容が読み取られます。
ステファンシャゼル

確かに、readが何をするのか理解しています。私が理解できないのは、バックグラウンドプロセスでreadを使用して端末から読み取ると、bashでブロックされますが、zshではブロックされない理由です。
a3nm

@ a3nm、どういう意味かわかりません。あなたができるreadことはどういう意味ですか、それは動作しますか?
ステファンシャゼル

私は、zshを使えば、あなたができることを言っているだけread | program > outputで、あなたが提案したのと同じように機能します。(そして、理由は
わかり

0

StéphaneChazelasのread ソリューションは、読み取りfdがで開かれた場合、Mac OS Xでも動作し/dev/fd/1ます。

# using bash on Mac OS X
# -bash: /dev/fd/1: Permission denied
read x </dev/fd/1 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  1 0

exec 3<&- 3</dev/fd/1
read x 0<&3 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  0 0

殺すことができるようにtail -f /dev/null(例えば、SIGINTで)スクリプトでは、背景に必要となるtailコマンドとwait

#!/bin/bash
# ctrl-c will kill tail and exit script
trap 'trap - INT; kill "$!"; exit' INT
exec tail -f /dev/null & wait $!

-2

/dev/zero標準入力としてリダイレクト!

program < /dev/zero > output &

9
これは、彼のプログラムに無限の数のゼロバイトを与えます...悲しいことに、それはそれをビジーループにします。
ジャンダー

1
これは本当のジャンダーではありません。/dev/zeroは決して閉じず、パイプチェーンを開いたままにします。ただし、ポスターには標準入力を使用しないため、ゼロがプログラムに転送されることはありません。これはビジーループではなく、純粋な待機です。
sillyMunky

2
申し訳ありませんが、OPはstdinを使用するため、これにより入力が消去され、/ dev / zeroから描画されます。次回は2回読む必要があります!OPがstdinを使用していなかった場合、これは私が見た中で最もエレガントなソリューションになり、忙しい待ち時間にはなりません。
sillyMunky
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.