GNU/Linux >> Linux Esercitazione >  >> Linux

Come reindirizzare le informazioni sull'errore del programma C eseguibile su Stdout? (Mac Os X)?

Voglio scrivere un programma di controllo automatico in C.
Ad esempio, ho un programma giocattolo "ciao.c":

#include <stdio.h>

int main()
{
    int a, b;

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

    return 0;
}

Ed ecco il mio file di input “1.in”:

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

e file di output “1.out”:

3
9
20
4
5
11

Uso "gcc hello.c -o hello.o" per compilare e generare un programma eseguibile "hello.o". Ovviamente, il programma incontrerà un "errore di segmento":(Esegui nel mio MAC OS X)

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

Ma voglio creare un controllo automatico usando pipe e diff:

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

E l'output è:

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

Nessun messaggio di errore visualizzato! Ma voglio visualizzarli nel terminale (MAC OS X).

Provo a reindirizzare stderr a stdout come:

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

Ma nessun effetto!

Provo anche a reindirizzare stderr a un file come:

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

e l'info "Errore di segmentazione:11" viene visualizzato nel terminale mentre nulla nel file.

La stessa situazione accade quando uso

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

Forse le informazioni sull'errore non sono in stderr.

Quindi, come posso risolvere questo problema? Grazie!

Risposta accettata:

NOTA: Ho sostituito hello.o con hello , poiché il .o l'estensione del file in questo contesto in genere denota un file oggetto e non il programma eseguibile finale.

Secondo il tuo post, vuoi eseguire il comando:

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

E vuoi che il messaggio di errore esegua ./hello <1.in per apparire nell'output di questo comando. Tuttavia, il messaggio di errore non proviene da hello.o programma stesso, ma dalla shell. La cosa più vicina a cui riesco a pensare per approssimare l'effetto desiderato con una singola riga è eseguire il comando in una subshell e quindi utilizzare questo output con il tuo diff comando:

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

Questo ci dà il seguente output:

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

L'unica differenza è che in questo caso si ottengono ulteriori metadati in uscita dalla shell (ovvero il numero di riga e la stringa di comando). Se vuoi replicare esattamente il messaggio di errore, puoi usare trap per inserire un gancio che stampi esattamente la stringa giusta.

Non riuscivo a trovare un modo per estrarre a livello di codice il messaggio di errore, quindi sono andato al codice sorgente di Bash e ho cercato il messaggio "Errore di segmentazione". L'ho trovato in un file chiamato siglist.c, insieme a un sacco di altri segnali e descrizioni di errori. Usando queste informazioni ho scritto il seguente script:

#!/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}"

Ora, usando questo script, possiamo eseguire il seguente comando:

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

Questo produce la stessa stringa dell'esecuzione di ./hello <1.in :

Segmentation fault: 11

Ma ora puoi catturare quella stringa dall'errore standard (stderr) e reindirizzarla a diff come volevi:

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

Questo produce l'output esatto che avresti ottenuto se il messaggio di errore fosse stato scritto nell'output standard che ti aspettavi inizialmente:

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

Linux
  1. Come utilizzare Nginx per reindirizzare

  2. Ssh – Reindirizza Stdout su Ssh?

  3. Come rendere eseguibile un programma da qualsiasi luogo?

  4. Come si esce dal programma X11 senza errori

  5. Come reindirizzare l'output del programma come input

Come reindirizzare da HTTP a HTTPS in Nginx

Come controllare la versione Java su Mac o Windows

Come risolvere ERR_TOO_MANY_REDIRECTS

Come reindirizzare stderr a stdout in Bash

Come rendere eseguibile un file in Linux

Come modificare l'indirizzo MAC in Linux