stdin を stdout でファイルにリダイレクトする

stdin を stdout でファイルにリダイレクトする

そこで、ユーザー入力を受け取り、その入力に基づいてテキストを出力するプログラムを作成しました。

編集2: C実行ファイルを実行し、ファイルからCプログラム入力を供給し、出力を別のファイルにリダイレクトするスクリプトを作成したいと思います。ただし、基本的に入力と出力を結合/マージして、入力に対して出力が印刷されるたびに入力も印刷したいと思います。そのため、ファイルに1行ずつ入力を供給し、入力ごとに出力をファイルに印刷し、これを続けます。プログラムを再実行したくはありません。入力ファイルの最後に到達するか、スクリプトからkill信号を送信するまで、プログラムが実行されたままにしたいのです。(クラスの採点スクリプトを作成しようとしています。学生がプログラムを提出し、私はこのスクリプトを実行してプログラムに入力を供給しますが、入力と出力を一緒に追跡したいので、各出力の入力を追跡しやすくなります) スクリプトの残りの部分を自分で作成する方法はわかりますが、入力と出力を組み合わせるところで行き詰まっています。

編集3: プログラムが何を出力するか分からないので、expect は機能しないと思います。私が知っているのは、プログラムが何を取り込むかだけです。たとえば、ある生徒のプログラムは「文字を入力してください:」と言うかもしれませんが、別の生徒のプログラムは「文字を入力してください-」と言うかもしれません。そのため、これらのプログラムから何を期待すればよいのかわかりません。

(注: 異なる形式の実行可能ファイルが多数ありますが、すべて同じ量の入力を求める必要があります)

たとえば、実行可能ファイルの 1 つは次のようになります。

"Enter a number: " (Wait for user input)
"Give another: "  (Wait for user input
"Total: " (Output based on input)
"Do you want to run again? "(Wait for user input)

編集: 私のスクリプトの主な目的は、ファイルからの入力を 1 行ずつ取り込んでプログラムを実行することです。たとえば、このプログラムでは、ファイル「input」を stdin として取り込みますが、stdout とマージされた stdin も追跡する必要があります。

./a.out < input > outputは次のように出力されることがわかります。

Enter a number: 
Give another:  
Total:  15
Do you want to run again? 

ただし、入力が欠落しています。入力は 7、8 N、5、10 N などになる可能性があるため、出力ファイルだけを見て、出力に基づいて入力が何であったかを知ることができます。これを含めたいのです。

答え1

私の理解が正しければ、標準入力からデータを読み取るタイミングを検出し、そのデータを送信し、対話型で実行するときにローカルを端末にa.outシミュレートするために stdout がリダイレクトされる同じログ ファイルにそのデータを書き込むことを希望しているということですか?echo

その場合、解決策 (bash 構文) は次のようになります。

mkfifo strace.fifo
{
  while read -d, trace; do
    if [[ $trace = *"read(0" ]]; then
      IFS= read -rn1 answer <&3 || break
      answer=${answer:-$'\n'}
      printf %s "$answer" >&2
      printf %s "$answer"
    fi
  done < strace.fifo 3< answers.txt |
    strace -o strace.fifo -e read ./a.out
} > log 2>&1

アイデアは、strace(Linux を使用している場合) を使用してreadシステム コールをトレースし、ファイル記述子 0 に がある場合はread、 から一度に 1 文字ずつフィードすることですanswers.txt

編集: プログラムが stdio などを使用している場合。出力が通常のファイルにリダイレクトされ、ターミナルではなくなると、出力されているすべてのプロンプトがバッファリングされ、プログラムが終了するときにのみフラッシュされる可能性があります。

回避策としては、 :を にstdbuf置き換えることです。これにより、アプリケーション (動的にリンクされたアプリケーションであり、バッファリングが stdio によるものであると想定) は、stdout が端末であるかのように行バッファリングを行うようになります。ただし、stdin/stdout が端末である場合に通常行われるように、stdio が stdin から読み取ったときに stdout をフラッシュすることはできません。たとえば、改行文字で終了しないプロンプトは、明示的な改行文字または改行文字が最終的に書き込まれるまで表示されません。したがって、バッファリングを完全に無効にするには、 を使用するのがおそらく最善でしょう。./a.outstdbuf -oL ./a.outfflushstdbuf -o0

a.outプロセスまたはスレッドをフォークする可能性がある場合には、-fにオプションを追加しますstrace

アプリケーションがselectまたはpollシステム コールを使用して、実際に を実行する前に stdin に読み取るものがあるかどうかを確認する場合、この方法は機能しませんread。また、非ブロッキング I/O によって、データが速すぎる速度で送信される可能性もあります。

コメントで述べたように、expectこれはユーザーインタラクションをシミュレートするツールであり、疑似端末を使用するため、入力エコーが自動的に取得され、バッファ出力問題。 の代わりとしてstdbufunbufferに付属するスクリプトを使用して擬似端末でラップすることもできます。その場合、 が標準出力にプロンプ​​トを再現できるa.outように、読み取りの検出と応答の送信の間に少し遅延を追加することをお勧めします。expect

答え2

これに使用しますscript。まさにこれがこのために作られたものです。

script /tmp/logfile -c 'your command here'

例えば:

>> script /tmp/log -c 'read -p "Value: " value; echo "value=$value"'
Script started, file is /tmp/log
Value: foo
value=foo
Script done, file is /tmp/log

>> cat /tmp/log
Script started on Wed 01 May 2013 01:16:34 PM EDT
Value: foo
value=foo

Script done on Wed 01 May 2013 01:16:35 PM EDT

関連情報