61446


C言語で標準入力のあるプログラムをコンパイルして他の言語から実行したいのですが,入力は事前に与えるのではなくユーザーが任意のタイミングで入力したいと思っています.

言語は問いません.  
このような機能は実現可能でしょうか?

例:

[code]

    #include <stdio.h>
    
    int main(){
      int a;
      scanf("%d", &a);
      printf("%d\n", a);
      return 0;
    }
    
[/code]

上のプログラムを他の言語で実行してscanf()のところで入力待ち状態となり,
ユーザーが他の言語で入力したタイミングでaに値が代入されるというようなプログラムです.  
よろしくお願いします.

[追記]  
具体的な例として以下のようなCのプログラムがあってそれをPythonでインターラクティブに実行したいです.

[code]

    #include <stdio.h>
    
    int main(){
      int a;
      scanf("%d", &a);
      printf("output: %d\n", a);
      scanf("%d", &a);
      printf("output: %d\n", a);
      return 0;
    }
    
[/code]

Pythonのコード(動かない)

[code]

    import subprocess
    
    p = subprocess.Popen(["./a.out"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    while p.poll() is None:
        p.stdin.write(str(input()).encode())
        p.stdin.write('\n'.encode())
        p.stdin.flush()
        print(p.stdout.readline().decode().strip())
    
[/code]

上のPythonコードは最終行のp.stdout.readline()のところで止まってしまいます.


CC BY-SA 4.0
2019-12-14T16:08:42.373
61444
2019-12-15T05:53:51.413
2019-12-15T02:24:38.090
37067
37067
question
linux c unix
scanfを含むCプログラムを他の言語からインタラクティブに実行したい


OSの機能なので、言語とは直接は関係ありません。  
子プロセスを起動できる言語(と言うか処理系(コンパイラ/インタプリタ/コマンド等))ならば、大概は備えているものでしょう。

例えば C言語ならばこんな記事があります。  
[メモ
UNIXの子プロセスの標準入力にパイプでデータを渡したい](https://qiita.com/hifistar/items/20a5dc1d66d85aac602f)

> やりたいこと  
>  UNIXで子プロセスを起動して任意のコマンドをexecで実行したい。  
>  そのコマンドの標準入力に対してパイプでデータを渡したい。
>
> プログラム例  
>  子プロセスを起動してcatを引数なしで呼ぶ。catは引数なしなので標準入力を待つ。  
>  親プロセスからは"Hello, World."をパイプで流す。
>
> つまり、shellで
>
> $ echo "Hello, World" | cat
>
> を実行したのと同じ。

[execlp redirect stdin in c](https://stackoverflow.com/q/22245237/9014308)

[C/pipe使っての子プロセスの標準入出力奪取](http://peridotto.com/wiki/index.php?C%2Fpipe%BB%C8%A4%C3%A4%C6%A4%CE%BB%D2%A5%D7%A5%ED%A5%BB%A5%B9%A4%CE%C9%B8%BD%E0%C6%FE%BD%D0%CE%CF%C3%A5%BC%E8)

> 子プロセスをexecした後に、標準入出力を親側で操作するサンプル書いたので保存。

逆方向(子プロセスの出力を受け取る)の説明が中心ですが、図で分かりやすそうなのがこの記事  
[親プロセス・子プロセス間通信](https://qiita.com/SoyaTakahashi/items/f28d0b5ef404afd339fa)

* * *

Pythonだとこんな記事が。

[subprocess – プロセスを生成して連携する](http://ja.pymotw.com/2/subprocess/)

> 別のコマンドと相互にやり取りする  
>  上述した全てのサンプルは制限のあるプロセス間のやり取りを前提としていました。 communicate()
> メソッドは全ての出力を読み込み、値を返す前に子プロセスの終了を待ちます。また Popen
> インスタンスが使用する個々のパイプハンドラに読み書きすることもできます。

[subprocessについてより深く（3系，更新版）](https://qiita.com/HidKamiya/items/e192a55371a2961ca8a4)

> インタラクティブ入出力  
>  何回かに分けて入力を送り，その都度出力を得る，といったやり取りは，下記のようにして実現される．参考にしたのはこの記事．  
>  一度にデータの入出力を終えるcommunicate()では再現できないため，大きなデータのやり取りが必要になると，デッドロックが発生するリスクがある．

* * *

なお、こちらの承認済み回答はOSに関係なくブロックせずにストリームを読み取るための信頼できる方法があると書いています。  
[Non-blocking read on a subprocess.PIPE in
python](https://stackoverflow.com/q/375427/9014308)

> A reliable way to read a stream without blocking regardless of operating
> system is to use
> [Queue.get_nowait()](https://docs.python.org/3/library/queue.html#queue.Queue.get_nowait):
>
> オペレーティングシステムに関係なくブロックせずにストリームを読み取るための信頼できる方法は、以下を使用すること Queue.get_nowait()
> です。

以下は回答のコピーで検証はしていません。

>
[code]

>     import sys
>     from subprocess import PIPE, Popen
>     from threading  import Thread
>  
>     try:
>         from queue import Queue, Empty
>     except ImportError:
>         from Queue import Queue, Empty  # python 2.x
>  
>     ON_POSIX = 'posix' in sys.builtin_module_names
>  
>     def enqueue_output(out, queue):
>         for line in iter(out.readline, b''):
>             queue.put(line)
>         out.close()
>  
>     p = Popen(['myprogram.exe'], stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
>     q = Queue()
>     t = Thread(target=enqueue_output, args=(p.stdout, q))
>     t.daemon = True # thread dies with the program
>     t.start()
>  
>     # ... do other things here
>  
>     # read line without blocking
>     try:  line = q.get_nowait() # or q.get(timeout=.1)
>     except Empty:
>         print('no output yet')
>     else: # got line
>         # ... do something with line
>  
[/code]

**またコメントが多数ついているので、色々と注意事項がありそうです。**

一方、上記記事の回答にもありますが、Unix系のシステムだと、PIPEをノンブロッキングモードに設定できるようです。

> On Unix-like systems and Python 3.5+ there's
> [os.set_blocking](https://docs.python.org/3/library/os.html#os.get_blocking)
> which does exactly what it says.
>
> UnixライクなシステムとPython 3.5+ os.set_blockingでは、まさにそれが言っていることを行います。

`import os`と`os.set_blocking(p.stdout.fileno(), False)`で設定できるようです。  
すると`p.stdout.readline()`がノンブロッキングモードになるので、その対策も必要です。

[os.set_blocking(fd,
blocking)](https://docs.python.org/ja/3/library/os.html#os.set_blocking)

> 指定されたファイル記述子のブロッキングモードを設定します。 ブロッキングが False の場合 O_NONBLOCK
> フラグを設定し、そうでない場合はクリアします。  
>  get_blocking() および socket.socket.setblocking() も参照してください。  
>  利用可能な環境: Unix。  
>  バージョン 3.5 で追加.

* * *

JAVAは基本的な状態がそれに該当するものがあるとか。

[java.lang
クラスProcess](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Process.html)

>
> デフォルトでは、作成されたサブプロセスは、自身の端末またはコンソールを持ちません。その標準入出力(つまり標準入力、標準出力、標準エラー)の処理はすべて親プロセスにリダイレクトされますが、それらの情報にアクセスするには、メソッドgetOutputStream()、getInputStream()、およびgetErrorStream()を使って取得されるストリームを使用します。

* * *

Rubyではこれでしょう。

Ruby 2.6.0 リファレンスマニュアル  
[module function Open3.#popen3](https://docs.ruby-
lang.org/ja/latest/method/Open3/m/popen3.html)

> 外部プログラム cmd を実行し、そのプロセスの標準入力、標準出力、標準エラー出力に接続されたパイプと実行したプロセスを待つためのスレッドを 4
> 要素の配列で返します。

Rubyで外部コマンドを実行して結果を受け取る方法あれこれ (1.9.3の記事)  
[Open3.popen3](https://qiita.com/tyabe/items/56c9fa81ca89088c5627#open3popen3)

> 実行中プロセスの標準出力、標準エラー出力をリアルタイムに扱いたい場合に便利  
>  ブロックを渡すことで、実行中プロセスの標準出力、標準エラー出力を扱える
>
> stdin : 渡せる  
>  stdout : 取れる  
>  stderr : 取れる  
>  status : 取れる


CC BY-SA 4.0
2019-12-14T23:13:49.697
61446
2019-12-15T05:53:51.413
2019-12-15T05:53:51.413
26370
26370
61444
answer