Ich habe also ein Programm, das Benutzereingaben entgegennimmt und basierend auf der Eingabe Text ausgibt.
EDIT2: Ich möchte ein Skript erstellen, das eine ausführbare C-Datei ausführt und das C-Programm mit Eingaben aus einer Datei versorgt und die Ausgabe in eine andere Datei umleitet. Ich möchte jedoch auch die Eingaben ausdrucken, wenn eine Ausgabe für die Eingabe gedruckt wurde, also im Grunde die Eingabe und die Ausgabe miteinander kombinieren/zusammenführen. Ich füge also die Eingaben Zeile für Zeile in eine Datei ein und drucke dann die Ausgabe für jede Eingabe in eine Datei aus und mache das so weiter. Ich möchte das Programm nicht erneut ausführen. Ich möchte, dass das Programm weiterläuft, bis es das Ende der Eingabedatei erreicht oder bis ich ihm ein Kill-Signal vom Skript aus sende. (Ich versuche, ein Bewertungsskript für eine Klasse zu erstellen. Die Studenten reichen ihre Programme ein und ich führe dieses Skript aus und füge ihren Programmen Eingaben hinzu, aber ich möchte die Eingabe + Ausgabe zusammen im Auge behalten, damit es für mich einfacher ist, die Eingabe für jede ihrer Ausgaben im Auge zu behalten.) Ich kann selbst herausfinden, wie ich den Rest des Skripts erstellen kann, aber ich komme einfach nicht weiter, wenn es darum geht, Eingabe + Ausgabe zusammenzuführen.
Edit3: Ich glaube nicht, dass expect funktioniert, weil ich nicht wissen kann, was das Programm ausgeben wird. Ich weiß nur, was es aufnehmen soll. Beispielsweise könnte ein Programm für einen Studenten „Gib mir ein Zeichen:“ sagen, während ein anderer sagt „Gebe ein Zeichen ein-“, also weiß ich nicht, was ich von diesen Programmen erwarten soll.
(Hinweis: Ich werde viele verschiedene ausführbare Dateien haben, die unterschiedliche Formate haben, aber alle die gleiche Menge an Eingaben erfordern sollten.)
Eine der ausführbaren Dateien könnte beispielsweise folgende sein:
"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)
BEARBEITEN: Das Hauptziel meines Skripts besteht darin, das Programm auszuführen, indem es die Eingaben zeilenweise aus einer Datei aufnimmt. Für dieses Programm möchte ich beispielsweise, dass es die Datei „input“ als stdin aufnimmt, aber ich möchte auch den Überblick über die mit stdout zusammengeführte stdin behalten.
Ich weiß also, dass ./a.out < input > output ausgeben wird
Enter a number:
Give another:
Total: 15
Do you want to run again?
Es fehlt jedoch die Eingabe, die ich ebenfalls einschließen möchte, sodass ich anhand der Ausgabe erkennen kann, was die Eingabe war, indem ich NUR die Ausgabedatei ansehe, da die Eingabe 7 8 N oder 5 10 N oder etwas in der Art sein könnte.
Antwort1
Wenn ich das richtig verstehe, möchten Sie erkennen, wann a.out
Daten von der Standardeingabe gelesen werden und wann diese Daten gesendet werden und auch in dieselbe Protokolldatei schreiben, zu der stdout umgeleitet wird, um echo
bei interaktiver Ausführung die lokale Ausgabe auf dem Terminal zu simulieren?
Dann wäre eine Lösung (Bash-Syntax) vielleicht so etwas wie:
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
Die Idee besteht darin, strace
(vorausgesetzt Sie verwenden Linux) die read
Systemaufrufe zu verfolgen und immer, wenn ein read
Dateideskriptor mit der Zahl 0 vorliegt, jeweils ein Zeichen von einzugeben answers.txt
.
Bearbeiten: wenn das Programm stdio oder etwas Ähnliches verwendet. Wenn die Ausgabe in eine normale Datei umgeleitet wird und kein Terminal mehr ist, passiert wahrscheinlich, dass alle ausgegebenen Eingabeaufforderungen gepuffert und erst am Ende gelöscht werden, wenn das Programm beendet wird.
Eine Problemumgehung wäre stdbuf
, : ./a.out
durch zu ersetzen stdbuf -oL ./a.out
. Dies würde der Anwendung (vorausgesetzt, es handelt sich um eine dynamisch verknüpfte Anwendung und die Pufferung erfolgt aufgrund von stdio) sagen, dass sie Zeilenpufferung auf stdout durchführen soll, als wäre es ein Terminal. Es würde jedoch immer noch nicht stdout leeren, wenn stdio von stdin liest, wie es normalerweise der Fall wäre, wenn stdin/stdout Terminals wären. So würde beispielsweise eine Eingabeaufforderung, die nicht durch ein Zeilenumbruchzeichen beendet wird, erst angezeigt, wenn ein explizites Zeichen fflush
oder ein Zeilenumbruchzeichen geschrieben wird. Am besten wäre es also wahrscheinlich, stdbuf -o0
die Pufferung vollständig zu deaktivieren.
Wenn a.out
Prozesse oder Threads verzweigt werden können, fügen Sie die -f
Option hinzu strace
.
Dieser Ansatz würde nicht funktionieren, wenn die Anwendung Systemaufrufe verwendet, select
um poll
zu prüfen, ob auf stdin etwas zu lesen ist, bevor sie dies tatsächlich ausführt read
. Nicht blockierende E/A kann auch dazu führen, dass wir Daten zu schnell senden.
Wie in den Kommentaren erwähnt. expect
ist das Tool zur Simulation der Benutzerinteraktion, es verwendet ein Pseudoterminal, so dass Sie automatisch das Eingabeecho erhalten und nicht diegepufferte AusgabeProblem. Als Alternative zu können Sie das mitgelieferte Skript stdbuf
verwenden, um ein Pseudoterminal einzubinden. In diesem Fall möchten Sie möglicherweise eine kleine Verzögerung zwischen dem Erkennen eines Lesevorgangs und dem Senden der Antwort einfügen, damit die Eingabeaufforderungen auf der Standardausgabe reproduziert werden können.unbuffer
a.out
expect
Antwort2
Verwenden Sie script
es hierfür. Genau dafür wurde es gemacht.
script /tmp/logfile -c 'your command here'
Zum Beispiel:
>> 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