![Finalizando o redirecionamento de entrada de loop infinito do processo](https://rvso.com/image/31660/Finalizando%20o%20redirecionamento%20de%20entrada%20de%20loop%20infinito%20do%20processo.png)
Editar: percebi que o programa que eu estava tentando executar tinha um loop infinito depois de verificar todas as minhas entradas. Depois é só imprimir infinitamente para nunca ler o EOF. Ele lerá a última entrada e entrará em um loop infinito
Por exemplo, digamos que o programa seja algo assim.
printf("%c\n", getch());
while(1)
{
printf("%c\n", getch());
}
Existe uma maneira de encerrar o programa depois de ler todas as minhas entradas? Quero poder encerrar o programa quando ele terminar de redirecionar o arquivo de entrada. (Quando o programa obtém o último caractere do arquivo de entrada) Nota: não posso modificar o programa que estou executando, mas posso modificar o script que executa este programa.
No momento, tenho isso em meu script para executar o programa. Basicamente, isso me ajuda a combinar/mesclar entrada + saída.
EDIT: Alguém me ajudou a resolver meu problema anterior. Eu deveria adicionar || quebrar esse strace, mas tenho um novo problema que está na edição no topo.
mkfifo strace.fifo
{
while read -d, trace; do
if [[ $trace = *"read(0" ]]; then
IFS= read -rn1 answer <&3 || break
echo "$answer" >> in
answer=${answer:-$'\n'}
printf %s "$answer" >&2
printf %s "$answer"
fi
done < strace.fifo 3< input | strace -o strace.fifo -e read stdbuf -o0 ./a.out &
} >> $fname.out 2>&1
Então, agora eu tenho uma maneira realmente hackeada de tentar encerrar o programa usando sleep e encerrando o programa. Também estou verificando a entrada usada até agora e comparando-a com o arquivo de entrada. Este é apenas um pequeno exemplo do que estou fazendo, meu script atual tem vários temporizadores e comparações semelhantes ao código abaixo. No entanto, esta forma não é uma boa maneira, porque se o programa não terminar de ler o arquivo de entrada após qualquer segundo que eu coloquei, ele não matará o programa. No meu script real, usei várias dessas instruções if e funciona 80% do tempo, mas às vezes não funciona corretamente, provavelmente por causa do cronômetro e da flutuação na maneira como o programa é executado.
sleep .05
awk 'BEGIN{ORS="";} NR==1{print; next;} /^[^ ]/ { print; next; } {print "\n";}' in > temp
diff -w -B temp input > /dev/null
# Check if input done yet
if [ $? -eq 0 ] ; then
# Check if program still running and input done
if [ "$(pidof a.out)" ] ; then
killall -15 a.out > /dev/null 2>&1
fi
fi
Então, estou me perguntando se existe uma maneira de fazer kill
o processo strace
após a entrada ser concluída? Também quero poder manter a entrada e a saída mescladas.
Responder1
Acho que tenho uma solução muito mais fácil, mas não tenho certeza de quão portátil ela é. Considerar:
$ cat trunc.c
#include <stdio.h>
int main() {
int c;
while(((c = getchar()) != EOF) && ((c & 0xff) != 0xff))
putchar(c);
return 0;
}
Isso explora o fato de que em uma máquina com complemento de dois (-1 & 0xff) == 0xff
. Isso captura seu programa que imprime EOF como um caractere. Eu testei:
your_buggy_source_gen < any_ascii_file | trunc
o que é equivalente a cat any_ascii_file
desde que não haja octetos de valor 0xff nele.
Responder2
"Agora estou me perguntando se existe uma maneira de verificar se o programa entra em um loop infinito antes que toda a entrada seja lida. Por exemplo, se um programa entra em um loop infinito, é a única maneira de interrompê-lo."
Nós sabemos a resposta paraessa pergunta por quase oitenta anos. A resposta é não, não há jeito.
Obrigado por fazer uma pergunta que não chegava nem perto da sua pergunta real:
"Estou tentando avaliar o resultado do aluno. Só quero criar um script para poder usar no futuro. No momento, estou funcionando muito bem usando um temporizador, mas quero tornar o script mais robusto sem um temporizador"
Solução simples:
# how many seconds of CPU (not wall clock)
# should the student's program get?
# 10 seconds is generous for an intro class
# 60 seconds of CPU would be obscene
$ ulimit -t 10
$ run_student_program
# but since I don't have a student program
$ time dd if=/dev/zero of=/dev/null
Killed
real 0m9.998s
user 0m3.080s
sys 0m6.912s
Responder3
Não é exatamente uma dica de programação shell, mas a realidade é que você precisa modificar o comportamento do programa quebrado, mesmo que não consiga modificar seu código-fonte.
Uma maneira de fazer isso seria um módulo LD_PRELOAD que intercepta a chamada do sistema "read()", de uma forma que invoca a chamada do sistema "read()" real e então sai quando encontra uma condição de fim de arquivo. (Idealmente eu interceptaria "getchar ()", mas geralmente é uma macro em vez de uma chamada de função, portanto não pode ser interceptada.)
Outra maneira seria executar o código em um depurador, descobrir onde ele entra no loop infinito e, em seguida, corrigir o binário, modificando o arquivo executável ou, novamente, aplicando um módulo LD_PRELOAD que substitui a função errante.
Ou você pode fazer como a resposta anterior sugere e canalizar a saída para algo que feche sua entrada quando o programa errante gerar algo que indique que atingiu o final de sua entrada. (Observe que isso depende dissonãocapturando SIGPIPE, o que é uma suposição justa neste caso.)
Uma versão mais sofisticada disso seria compartilhar o descritor de arquivo de entrada com outro programa que não o leia, mas monitore para ver se ele atingiu seu fim. No entanto, isso é algo particularmente complicado de fazer, especialmente se você estiver lidando com canos, tomadas ou dispositivos.
Supondo que seu programa incorreto esteja lendo stdin, envolva-o com algo assim:
#!/bin/sh executar-programa-ruim "$@" & pid=$! perl -MFcntl=:modo -e ' @S = stat STDIN ou die "Entrada inválida; $!\n"; S_IFREG($S[2]) ou die "A entrada não é um arquivo simples\n"; enquanto (sysseek(STDIN,0,1) != $S[7]) { dormir 1 } ' matar $pid espere
Responder4
Você realmente deveria consertar o programa quebrado, mas se não puder, você pode contornar isso fazendo com que o shell cat o arquivo e canalize-o para o programa, depois durma por um ou dois segundos antes de sair, fechando assim o canal e matando o programa com SIGPIPE.
(cat file ; sleep 2) | stupid_program