標準入力からキー入力を受けるプログラムを、シェルスクリプト等ターミナル以外からバックグラウンド実行すると、EOFを読み続ける状態になるようです。
ちょっとしたキー入力処理を付けた以下のようなプログラムを用意しました。
int main(int argc, char* argv[]) { spawnTask(); // スレッドを生成しタスク実行 while (true) { std::string entered; std::cout >> "command> "; std::cin >> entered; // (1) if (entered == "dump") { dumpStatus(); } } }
通常は、(1)でキー入力があるまでブロックします。ところが、スクリプト等からバックグラウンド実行すると、標準入力が閉じられるためか(?)、(1)ではブロックせずに、enteredはから文字列(empty() == true)となってwhile文がまわり続けます。
標準入力をFIFOに結びつける
FIFOに結びつけるとうまくいくかと思い実験しました。
keyinprocess < /tmp/keyin &
上記のスクリプトを実行します。なお、あらかじめmkfifoで/tmp/keyinを作成しておきます。
最初は、echoコマンドでFIFOに文字列を出力してみました。
$ echo dump > /tmp/keyin $
"dump"がstd::cinから読み込み処理が起動しますが、その後はEOF状態となってstd::cinがブロックせずループ状態となります。
FIFOは書き込み側がクローズすると、読み出し側はEOFとなるので、echoコマンドが1回終了するとクローズとなるからのようです。
次は、コマンドが終了しなければいいと考えて、
$ cat > /tmp/keyin dump hello dump
と実行すると、クローズしてEOFになることはなく、キー入力処理が想定どおりに回ります。
ただ、このcatを終了させると、やはりEOFで無限ループ状態になります。
FIFOは複数プロセスが書き込みできるので、上記のFIFOに複数書き込みを行うプロセスを動かしておくことで、回避できます。
とはいえ、キー入力のループにエラー処理を追加した方がよいですね。
std::cin >> entered; if (entered.empty()) { break; } else if (entered == "dump") { ...