Перенаправление stdin с stdout в файл

Перенаправление stdin с stdout в файл

Итак, у меня есть программа, которая принимает вводимые пользователем данные и выводит текст на основе введенных данных.

EDIT2: Я хочу создать скрипт, который запускает исполняемый файл C, и скрипт подает входные данные программе C из файла и перенаправляет выходные данные в другой файл. ОДНАКО я также хочу распечатать входные данные всякий раз, когда вывод был напечатан для ввода, в основном объединяя/сливая входные данные и выходные данные вместе. Поэтому я показываю ему входные данные построчно в файле, а затем печатаю выходные данные в файл для каждого входного файла и продолжаю это делать. Я не хочу перезапускать программу, я хочу, чтобы программа продолжала работать, пока не достигнет конца входного файла или пока я не отправлю ей сигнал завершения из скрипта. (Я пытаюсь создать скрипт оценки для класса. Учащиеся отправляют свои программы, а я запускаю этот скрипт и подаю входные данные их программам, но я хочу отслеживать входные данные и выходные данные вместе, чтобы мне было проще отслеживать входные данные для каждого их выходных данных) Я могу придумать, как создать остальную часть скрипта сам, но я просто застрял на объединении входных данных и выходных данных.

Edit3: Я не думаю, что expect будет работать, потому что я не могу знать, что выведет программа. Я знаю только то, что она должна принимать. Например, у одного студента может быть программа, которая говорит "Введите мне символ:", а у другого - "Введите символ-", поэтому я не знаю, чего ожидать от этих программ.

(Примечание: у меня будет много разных исполняемых файлов, которые будут иметь разный формат, но все они должны запрашивать одинаковый объем входных данных)

Например, один из исполняемых файлов может быть таким:

"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)

EDIT: Моя главная цель скрипта — запустить программу, принимающую входные данные из файла построчно. Например, для этой программы я хочу, чтобы она принимала файл «input» как stdin, но я также хочу отслеживать stdin, объединенный со stdout.

Так что я знаю, что ./a.out < input > output выведет

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

Однако в нем отсутствуют входные данные, которые я также хотел включить, чтобы я мог определить, какие были входные данные, основываясь на выходных данных, просто посмотрев ТОЛЬКО на выходной файл, поскольку входные данные могут быть 7 8 Н или 5 10 Н или что-то в этом роде.

решение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системных вызовов и всякий раз, когда есть readфайловый дескриптор 0, передавать по одному символу за раз из answers.txt.

Редактировать: если программа использует stdio или что-то подобное. Что, скорее всего, произойдет, когда вывод будет перенаправлен в обычный файл и больше не будет терминалом, так это то, что все выводимые им приглашения будут буферизированы и будут очищены только в конце, когда программа завершит работу.

Обойти это можно, используя stdbuf: заменить ./a.outна stdbuf -oL ./a.out. Это сообщит приложению (предполагая, что это динамически связанное приложение и буферизация происходит из-за stdio) о необходимости буферизации строк на stdout, как если бы это был терминал. Однако, чего бы оно все равно не делало, так это очистки stdout при чтении stdio из stdin, как это обычно происходит, если бы stdin/stdout были терминалами. Так что, например, приглашение, не завершенное символом новой строки, не будет отображаться до тех пор, пока явное fflushили пока символ новой строки не будет в конечном итоге записан. Поэтому лучшим, вероятно, будет использовать stdbuf -o0для полного отключения буферизации.

Если a.outвозможно разветвление процессов или потоков, добавьте эту -fопцию в strace.

Такой подход не сработает, если приложение использует системные вызовы selectили pollвызовы для проверки того, есть ли что-то для чтения на stdin перед фактическим выполнением read. Неблокируемый ввод-вывод также может привести к слишком быстрой отправке данных.

Как упоминалось в комментариях, expectэто инструмент для имитации взаимодействия с пользователем, он использует псевдотерминал, поэтому вы автоматически получите входное эхо и не будете иметьбуферизованный выводпроблема. В качестве альтернативы stdbufвы можете использовать unbufferскрипт, который идет с ним, чтобы обернуть его a.outв псевдотерминал. В этом случае вы можете добавить небольшую задержку между обнаружением чтения и отправкой ответа, чтобы позволить expectвоспроизвести подсказки на его stdout.

решение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

Связанный контент