Redirecionando stdin com stdout para arquivo

1

Portanto, eu tenho um programa que recebe entradas e saídas de texto do usuário com base na entrada.

EDIT2: Eu 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, eu também quero imprimir a entrada sempre que uma saída foi impressa para entrada, basicamente combinando / mesclando a entrada e a saída juntas. Então, eu o insiro linha por linha em um arquivo e, em seguida, imprimo a saída para um arquivo para cada entrada e continuo fazendo isso. Eu não quero re-executar o programa que eu quero que o programa ainda esteja em execução até que ele atinja o final do arquivo de entrada ou até que eu envie um sinal de kill do script. (Estou tentando fazer um roteiro de notas para uma classe. Alunos enviam seus programas e eu corro este script e eu insumo entrada para seus programas, mas eu quero acompanhar a entrada + saída juntos, assim fica mais fácil para mim acompanhar a entrada de cada uma das suas saídas) Eu posso descobrir como criar o resto do script sozinho, mas eu estou apenas preso em combinar entrada + saída juntos.

Edit3: Eu não acho que o esperado funcionará porque não tenho como saber o que o programa produzirá. Só sei o que é suposto aceitar. Por exemplo, um aluno pode ter um programa dizendo "Dê-me um caractere", enquanto outro dirá "Digite um caractere", portanto, não sei o que esperar desses programas.

(Nota: eu terei muitos executáveis diferentes que terão formato diferente, mas todos devem pedir a mesma quantidade de entrada)

Por exemplo, um dos executáveis pode 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 levando em entrada de um arquivo linha por linha. Por exemplo, para este programa, eu quero que ele pegue o arquivo "input" como stdin, mas também quero acompanhar o stdin mesclado com o stdout.

Então eu sei ./a.out < entrada > saída irá 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 o que a entrada foi baseada na saída apenas olhando para o arquivo de saída SOMENTE porque a entrada poderia ser 7 8 N ou 5 10 N ou algo parecido naquela.

    
por Strawz 01.05.2013 / 18:09

2 respostas

4

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, o stdout é redirecionado para simular a% localecho para o terminal quando executado interativamente?

Então talvez uma solução (bash syntax) seja 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 idéia é usar strace (supondo que você esteja no Linux), rastrear as chamadas do sistema read e sempre que houver um read no descritor de arquivo 0, alimente um caractere por vez de answers.txt .

Editar : se o programa usa stdio ou algo assim. O que é provável que aconteça quando a saída é redirecionada para um arquivo regular e não é mais um terminal é que todos os prompts que estão emitindo são armazenados em buffer e só serão liberados no final quando o programa sair.

Uma solução seria usar stdbuf : replace ./a.out with stdbuf -oL ./a.out . Isso diria ao aplicativo (supondo que é um aplicativo dinamicamente vinculado e o buffer é devido ao stdio) para fazer o buffer de linha no stdout como se fosse um terminal. No entanto, o que ainda não é liberar stdout em stdio reads de stdin como faria normalmente se stdin / stdout fosse terminais. Assim, por exemplo, um prompt não terminado por um caractere de nova linha não seria exibido até que um caractere fflush ou até que um caractere de nova linha seja escrito. Então, o melhor seria usar stdbuf -o0 para desativar completamente o buffer.

Se a.out puder separar processos ou threads, adicione a opção -f a strace .

Essa abordagem não funcionará se o aplicativo usar select ou poll chamadas do sistema para verificar se há algo para ler no stdin antes de realmente fazer o read . E / S sem bloqueio também podem nos fazer enviar dados muito rapidamente.

Como mencionado nos comentários. expect é a ferramenta para simular a interação do usuário, ele usa um pseudo-terminal, para que você obtenha automaticamente o eco de entrada e não tenha o problema saída em buffer . Como uma alternativa para stdbuf , você pode usar o script unbuffer que vem com ele para agrupar a.out em um pseudo-terminal. Nesse caso, você pode adicionar um pequeno atraso entre detectar uma leitura e enviar a resposta para permitir que expect reproduza os prompts em sua stdout.

    
por 01.05.2013 / 22:06
0

Use script para isso. Isso é exatamente o 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
    
por 01.05.2013 / 19:18