web-dev-qa-db-ja.com

リダイレクトされた入力と出力でプログラムのトランスクリプトをキャプチャする

私が書いたプログラムの典型的な相互作用は次のようになります。

Enter command: a_command
Completed a command

Enter command: another_command
Completed another command

私は通常、./program < input.txtのようにプログラムを実行します。ここで、input.txtには次のものが含まれます。

a_command
another_command

上記のように(出力だけでなく)インタラクション全体をキャプチャできるようにしたいです。どうすればbashでこれを行うことができますか?

編集:programはバイナリ(具体的にはC++)であり、bashスクリプトではありません。ソースコードにアクセスできますが、ソースコードを変更せずにこれを実行したいと思います。

2
karepker

対応するプロンプトの後に入力を出力するには、プログラムがいつ入力を待機しているかを知る必要があります。実行中のプログラムを観察することから判断する方法はありません。stdinへの入力を待機しているプログラムと、他の何か(ネットワーク、ディスク、計算など)を待機しているプログラムを区別することはできません。

したがって、インタラクティブな使用のように見えるトランスクリプトを取得するプロセスは、次のようにする必要があります。

  • プログラムを起動します。
  • 最初のプロンプトを待ち、認識します。
  • 入力を表示して、最初のプロンプトに送信します。
  • 入力の2番目のプロンプトとそれ以降のすべてのプロンプトについても同様です。
  • プログラムが終了したら終了します。

これをスクリプト化するための事実上の標準ツールは Expect です。スクリプトは次のようになります(警告:コードが機能しない、ブラウザーに直接入力):

#!/usr/bin/expect -f
set transcript_file [open "transcript" wb]
spawn myprogram
expect "Enter command:"
puts -nonewline $transcript_file $expect_out(buffer)
send "a_command\r"
puts -nonewline $transcript_file "a_command\r"
puts -nonewline $transcript_file $expect_out(buffer)
send "another_command\r"
puts -nonewline $transcript_file "another_command\r"
puts -nonewline $transcript_file $expect_out(buffer)
…
expect eof
close $transcript_file

行を追加しますset -xプログラムファイル内。

例:

#!/bin/bash
set -x #echo on

ls $PWD

これにより、すべての変数が展開され、コマンドの出力前に完全なコマンドが出力されます。

出力:

+ ls /home/user/
file1.txt file2.txt

Setコマンドのより類似したフラグについては、Stackoverflowの この回答 を確認してください。