Portanto, tenho um programa que recebe a entrada do usuário e gera texto com base na entrada.
EDIT2: Quero criar um script que execute um executável C e o script alimente a entrada do programa C de um arquivo e redirecione a saída para outro arquivo. NO ENTANTO, também quero imprimir a entrada sempre que uma saída for impressa para entrada, basicamente combinando/mesclando a entrada e a saída. Então, eu alimento a entrada linha por linha em um arquivo e, em seguida, imprimo a saída em um arquivo para cada entrada e continuo fazendo isso. Não quero executar novamente o programa, quero que o programa continue em execução até chegar ao final do arquivo de entrada ou até que eu envie um sinal de interrupção do script. (Estou tentando fazer um script de avaliação para uma turma. Os alunos enviam seus programas e eu executo esse script e alimento os programas deles, mas quero acompanhar a entrada e a saída juntos, para que seja mais fácil para mim. acompanhe a entrada de cada uma de suas saídas). Posso descobrir como criar o resto do script sozinho, mas estou preso em combinar entrada + saída.
Edit3: Não acho que expect funcione porque não tenho como saber o que o programa produzirá. Por exemplo, um aluno pode ter um programa dizendo "Dê-me um caractere:" enquanto outro dirá "Insira um caractere-", então não sei o que esperar desses programas.
(Nota: terei muitos executáveis diferentes que terão formatos diferentes, mas todos deverão solicitar a mesma quantidade de entrada)
Por exemplo, um dos executáveis poderia ser este:
"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: Meu principal objetivo do meu script é executar o programa recebendo informações de um arquivo linha por linha. Por exemplo, para este programa, quero que ele receba o arquivo "input" como stdin, mas também quero acompanhar o stdin mesclado com o stdout.
Então eu sei que ./a.out < input > output produzirá
Enter a number:
Give another:
Total: 15
Do you want to run again?
No entanto, está faltando a entrada que é o que eu quero incluir também, para que eu possa dizer qual entrada foi baseada na saída apenas olhando o arquivo de saída SOMENTE porque a entrada pode ser 7 8 N ou 5 10 N ou algo parecido.
Responder1
Se bem entendi, você deseja detectar quando a.out
está lendo dados da entrada padrão e quando envia esses dados e também grava esses dados no mesmo arquivo de log para o qual stdout é redirecionado para simular o local echo
para o terminal quando executado interativamente?
Então talvez uma solução (sintaxe bash) seria algo como:
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
A ideia é usar strace
(supondo que você esteja no Linux), para rastrear as read
chamadas do sistema e sempre que houver um read
descritor 0 no arquivo, alimentar um caractere por vez de answers.txt
.
Editar: se o programa usar stdio ou algo parecido. O que provavelmente acontecerá quando a saída for redirecionada para um arquivo normal e não for mais um terminal é que todos os prompts emitidos serão armazenados em buffer e só serão liberados no final, quando o programa for encerrado.
Uma solução alternativa seria usar stdbuf
: substitua ./a.out
por stdbuf -oL ./a.out
. Isso diria ao aplicativo (supondo que seja um aplicativo vinculado dinamicamente e o buffer seja devido ao stdio) para fazer o buffer de linha no stdout como se fosse um terminal. No entanto, o que ainda não faria é liberar stdout nas leituras de stdio de stdin, como faria normalmente se stdin/stdout fossem terminais. Assim, por exemplo, um prompt não terminado por um caractere de nova linha não seria exibido até que um fflush
caractere explícito ou de nova linha fosse eventualmente escrito. Então, provavelmente seria melhor usar stdbuf -o0
para desabilitar completamente o buffer.
Se a.out
for possível bifurcar processos ou threads, adicione a -f
opção a strace
.
Essa abordagem não funcionaria se o aplicativo usasse chamadas select
de poll
sistema para verificar se há algo para ler no stdin antes de realmente executar o read
. A E/S sem bloqueio também pode fazer com que enviemos dados muito rapidamente.
Conforme mencionado nos comentários. expect
é a ferramenta para simular a interação do usuário, ela usa um pseudo terminal, então você obteria automaticamente o eco de entrada e não teria osaída em bufferproblema. Como alternativa stdbuf
, você pode usar o unbuffer
script que vem com ele para encapsular a.out
um pseudo terminal. Nesse caso, você pode querer adicionar um pequeno atraso entre a detecção de uma leitura e o envio da resposta para permitir expect
a reprodução dos prompts em seu stdout.
Responder2
Use script
para isso. Foi exatamente para isso que foi feito.
script /tmp/logfile -c 'your command here'
Por exemplo:
>> 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