GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie leitet man Fehlerinformationen eines ausführbaren C-Programms nach Stdout um? (Mac OS X)?

Ich möchte einen automatischen C-Programmprüfer schreiben.
Zum Beispiel habe ich ein Spielzeugprogramm „hello.c“:

#include <stdio.h>

int main()
{
    int a, b;

    while (scanf("%d %d", (&a)-1000000000000000, &b) != EOF)
    {
        printf("%d\n", a+b);
    }

    return 0;
}

Und hier ist meine Eingabedatei „1.in“:

1 2
4 5
10 10
2 2
3 2
7 4

und Ausgabedatei „1.out“:

3
9
20
4
5
11

Ich verwende „gcc hello.c -o hello.o“, um ein ausführbares Programm „hello.o“ zu kompilieren und zu generieren. Offensichtlich trifft das Programm auf „Segmentfehler“:(Run in my MAC OS X)

$ ./hello.o <1.in
Segmentation fault: 11

Aber ich möchte einen automatischen Checker mit Pipe und Diff erstellen:

./hello.o <1.in | diff - 1.out

Und die Ausgabe ist:

0a1,6
> 3
> 9
> 20
> 4
> 5
> 11

Keine Fehlermeldungsanzeige! Aber ich möchte sie im Terminal anzeigen (MAC OS X).

Ich versuche, stderr wie folgt auf stdout umzuleiten:

./hello.o <1.in 2>&1 | diff - 1.out

Aber keine Wirkung!

Ich versuche auch, stderr in eine Datei umzuleiten wie:

./hello.o <1.in 2>log

und die Info „Segmentierungsfehler:11“ wird im Terminal angezeigt, obwohl nichts in der Datei ist.

Die gleiche Situation passiert, wenn ich

verwende
./hello.o <1.in &>log

Vielleicht ist die Fehlerinfo nicht in stderr.

Also, wie kann ich dieses Problem lösen? Vielen Dank!

Akzeptierte Antwort:

HINWEIS: Ich habe hello.o ersetzt mit hello , da die .o Die Dateierweiterung würde in diesem Zusammenhang normalerweise eine Objektdatei bezeichnen und nicht das endgültige ausführbare Programm.

Laut Ihrem Beitrag möchten Sie den Befehl ausführen:

./hello <1.in 2>&1 | diff - 1.out

Und Sie wollen die Fehlermeldung vom Ausführen von ./hello <1.in in der Ausgabe dieses Befehls erscheinen. Die Fehlermeldung kommt jedoch nicht von hello.o Programm selbst, aber von der Shell. Das Beste, was ich mir vorstellen kann, um den gewünschten Effekt mit einer einzigen Zeile zu erreichen, ist, den Befehl in einer Subshell auszuführen und dann diese Ausgabe mit Ihrem diff zu verwenden Befehl:

2>&1 bash -c './hello <1.in' | diff - 1.out

Dies gibt uns die folgende Ausgabe:

1c1,6
< bash: line 1: 58469 Segmentation fault: 11  ./hello < 1.in
---
> 3
> 9
> 20
> 4
> 5
> 11

Der einzige Unterschied besteht darin, dass Sie in diesem Fall einige zusätzliche Metadaten von der Shell erhalten (z. B. die Zeilennummer und die Befehlszeichenfolge). Wenn Sie die Fehlermeldung genau replizieren möchten, können Sie trap verwenden um einen Haken einzufügen, der genau die richtige Zeichenkette ausgibt.

Ich konnte keine Möglichkeit finden, die Fehlermeldung programmgesteuert zu extrahieren, also ging ich zum Bash-Quellcode und suchte nach der Meldung „Segmentation fault“. Ich habe es in einer Datei namens siglist.c gefunden, zusammen mit einer Reihe anderer Signale und Fehlerbeschreibungen. Mit diesen Informationen habe ich das folgende Skript geschrieben:

#!/bin/bash 

# trapdesc.sh
#
#   Take an error code from the `trap` command and
#   print out the corresponding error message.
#
#   Example usage:
#
#       (trap 'bash trapdesc.sh $?' EXIT; <COMMAND>)
#

# List of signal codes and corresponding error messages
#
# Taken from bash source (siglist.c):
#
#   https://github.com/tpruzina/bash/blob/master/siglist.c
#
declare -a SIGNALS=(
"SIGHUP":"Hangup"
"SIGINT":"Interrupt"
"SIGQUIT":"Quit"
"SIGILL":"Illegal instruction"
"SIGTRAP":"BPT trace/trap"
"SIGABRT":"ABORT instruction"
"SIGEMT":"EMT instruction"
"SIGFPE":"Floating point exception"
"SIGKILL":"Killed"
"SIGBUS":"Bus error"
"SIGSEGV":"Segmentation fault"
"SIGSYS":"Bad system call"
"SIGPIPE":"Broken pipe"
"SIGALRM":"Alarm clock"
"SIGTERM":"Terminated"
"SIGURG":"Urgent IO condition"
"SIGSTOP":"Stopped (signal)"
"SIGTSTP":"Stopped"
"SIGCONT":"Continue"
"SIGCLD":"Child death or stop"
"SIGTTIN":"Stopped (tty input)"
"SIGIO":"I/O ready"
"SIGXCPU":"CPU limit"
"SIGXFSZ":"File limit"
"SIGVTALRM":"Alarm (virtual)"
"SIGPROF":"Alarm (profile)"
"SIGWINCH":"Window changed"
"SIGLOST":"Record lock"
"SIGUSR1":"User signal 1"
"SIGUSR2":"User signal 2"
"SIGMSG":"HFT input data pending"
"SIGPWR":"power failure imminent"
"SIGDANGER":"system crash imminent"
"SIGMIGRATE":"migrate process to another CPU"
"SIGPRE":"programming error"
"SIGGRANT":"HFT monitor mode granted"
"SIGRETRACT":"HFT monitor mode retracted"
"SIGSOUND":"HFT sound sequence has completed"
"SIGINFO":"Information request"
)

# Make sure we get an integer 
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
    2>&1 echo "Not a signal identifier: $1"
    exit 1
fi

# Convert the signal from the `trap` function value to the signal ID
sid="$(($1 - 128))"

# Make sure the signal ID is in the valid range
if [[ "${sid}" -lt 0 || "${sid}" -gt 40 ]]; then
    2>&1 echo "Unrecognized signal: ${sid}"
    exit 1
fi

# Get the array-index for the signal
index="$((sid-1))"

# Get the signal description
description="$(echo ${SIGNALS[index]} | cut -d: -f2)"

# Print the error description
echo "${description}: ${sid}"

Mit diesem Skript können wir nun den folgenden Befehl ausführen:

(trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in)

Dies erzeugt dieselbe Zeichenfolge wie die Ausführung von ./hello <1.in :

Segmentation fault: 11

Aber jetzt können Sie diesen String aus dem Standardfehler (stderr) erfassen und an diff leiten wie du wolltest:

(2>&1 trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in) | diff - 1.out

Dies erzeugt genau die Ausgabe, die Sie erhalten hätten, wenn die Fehlermeldung in die ursprünglich erwartete Standardausgabe geschrieben worden wäre:

1c1,6
< Segmentation fault: 11
---
> 3
> 9
> 20
> 4
> 5
> 11

Linux
  1. So leiten Sie die Ausgabe in eine Datei und Stdout in Linux um

  2. Wie sende ich Stdout an mehrere Befehle?

  3. Wie leite ich die Ausgabe eines Programms in eine Zip-Datei um?

  4. Wie macht man ein Programm überall ausführbar?

  5. Wie erhalte ich die MAC-Adresse Ihres Computers mit einem C-Programm?

So leiten Sie HTTP zu HTTPS in Nginx um

So überprüfen Sie die Java-Version auf Mac oder Windows

Fehlerbehebung bei ERR_TOO_MANY_REDIRECTS

So leiten Sie stderr in Bash auf stdout um

Wie man eine Datei unter Linux ausführbar macht

So ändern Sie die MAC-Adresse in Linux