Bash入力リダイレクトを介して複数の読み取り(stdin)呼び出しに入力を提供する

Bash入力リダイレクトを介して複数の読み取り(stdin)呼び出しに入力を提供する

2回呼び出される次のプログラムがあるとしますread()

#include <stdio.h>
#include <unistd.h>

#define SIZE 0x100

int main(void)
{
    char buffer1[SIZE];
    char buffer2[SIZE];

    printf("Enter first input: \n");
    fflush(stdout);
    read(STDIN_FILENO, buffer1, SIZE);

    printf("Enter second input: \n");
    fflush(stdout);
    read(STDIN_FILENO, buffer2, SIZE);

    printf("\nFirst input:\n%s", buffer1);
    printf("\nSecond input:\n%s", buffer2);

    return 0;
}

直接呼び出すと、1最初の入力と22番目の入力を受け取り、印刷できます。

First input:
1

Second input:
2

入力リダイレクトを使用するときにこれを達成するには?

最初の方法は2つの入力を使用するため、次の方法は機能しませんread

パイプリダイレクト:

$ { echo "1"; echo "2"; } | ./main_read
Enter first input:
Enter second input:

First input:
1
2

Second input:

区切り文字リダイレクト:

$ ./main_read << EOF
1
2
EOF
Enter first input:
Enter second input:

First input:
1
2

Second input:

ソースコードを変更することはできませんし、入力が時々SIZE

2人目が残りの入力を使用できるread()ように、1人目に読書を停止するように指示する方法はありますか?read()

ベストアンサー1

これは許容可能な解決策を提供しないかもしれませんが、次の点を考慮してください。

  • ソースコードは変更できません

  • シェルは、実行中のプログラムの開かれたファイル記述子が指す場所を変更できず、実行中のプログラムにファイル記述子の読み取りを停止させることもできません。

競争条件を利用することに加えて、残りの選択肢のいくつかは次のとおりです。

  • SIZEプログラムが常に一度にバイトを入力していることを確認してください。

    {
      echo foo | dd bs=256 conv=sync
      echo bar | dd bs=256 conv=sync
    } 2>/dev/null | ./main_read
    

    出力:

    Enter first input: 
    Enter second input: 
    
    First input:
    foo
    
    Second input:
    bar
    

    これは、少なくともSIZEパイプバッファサイズより小さいと仮定する。

  • expect(またはそれに対応する)スクリプトでプログラム呼び出しをラップします。

    expect <<'EOT'
    spawn ./main_read
    expect "Enter first input:"
    send "foo\n"
    expect "Enter second input:"
    send "bar\n"
    expect eof
    EOT
    

    または、別のコマンドの出力をパイプできるように別々に読み込みます(OSがプロセスのファイル記述子を提供すると仮定/dev/fd/n)。

    echo foo | {
      echo bar |
        expect 4<&0 <<'EOT'
        spawn ./main_read
        set chan [open "/dev/fd/3"]
        gets $chan line
        expect "Enter first input:"
        send "$line\r"
        close $chan
        set chan [open "/dev/fd/4"]
        gets $chan line
        expect "Enter second input:"
        send "$line\r"
        close $chan
        expect eof
    EOT
    } 3<&0
    

    どちらの場合も、出力は次のようになります。

    spawn ./main_read
    Enter first input: 
    foo
    Enter second input: 
    bar
    
    First input:
    foo
    
    Second input:
    bar
    
  • 非ブロック方式でパイプを開くことができるシステム(Linuxなど)では、FIFOを使用してシェルにプログラムを読み書きすることができます。たとえば、

    makefifo fifo
    {
      exec 3<>fifo
      ./main_read 0<&3
    } |
    sh -c '
      # read a line from the pipe
      # read from a file or a different pipe, write to fifo
      # repeat ...
      # echo the output from the pipe
    ' mysh
    

    しかし、expect可能であれば、これを再創造しなければならない説得力のある理由はありません。

しかし、他の人が指摘したように、約束はありません。すべてのプログラムはread実際にSIZEバイトを取得します。

おすすめ記事