GNU/Linux >> Znalost Linux >  >> Linux

Jak přesměrovat informace o chybě spustitelného programu C na Stdout? (mac Os X)?

Chci napsat automatickou kontrolu programu C.
Mám například hračkářský program „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;
}

A zde je můj vstupní soubor „1.in“:

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

a výstupní soubor „1.out“:

3
9
20
4
5
11

Používám „gcc hello.c -o hello.o“ ke kompilaci a generování spustitelného programu „hello.o“. Je zřejmé, že program bude splňovat „chybu segmentu“:(Spustit v mém MAC OS X)

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

Ale chci udělat automatickou kontrolu pomocí potrubí a rozdílu:

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

A výstup je:

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

Žádné chybové hlášení! Ale chci je zobrazit v terminálu (MAC OS X).

Snažím se přesměrovat stderr na stdout jako:

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

Ale žádný efekt!

Snažím se také přesměrovat stderr do souboru jako:

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

a na terminálu se zobrazí informace „Segmentation fault:11“, zatímco v souboru není nic.

Stejná situace nastane, když použiji

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

Možná informace o chybě nejsou v stderr.

Jak tedy mohu tento problém vyřešit? Děkuji!

Přijatá odpověď:

POZNÁMKA: Nahradil jsem hello.o s hello , protože .o přípona souboru v tomto kontextu obvykle označuje objektový soubor a nikoli konečný spustitelný program.

Podle vašeho příspěvku chcete spustit příkaz:

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

A chcete, aby chybová zpráva při spuštění ./hello <1.in se objeví ve výstupu tohoto příkazu. Chybová zpráva však nepochází z hello.o program sám, ale ze shellu. Nejbližší věc, kterou mohu myslet na aproximaci požadovaného efektu pomocí jednoho řádku, je spustit příkaz v podshellu a poté použít tento výstup s vaším diff příkaz:

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

To nám dává následující výstup:

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

Jediný rozdíl je v tom, že v tomto případě získáte další výstup metadat pomocí shellu (tj. číslo řádku a řetězec příkazu). Pokud chcete chybovou zprávu přesně replikovat, můžete použít trap pro vložení háčku, který vytiskne přesně ten správný řetězec.

Nemohl jsem najít způsob, jak programově extrahovat chybovou zprávu, tak jsem šel do zdrojového kódu Bash a hledal zprávu „Chyba segmentace“. Našel jsem to v souboru s názvem siglist.c, spolu se spoustou dalších signálů a popisů chyb. Pomocí těchto informací jsem napsal následující skript:

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

Nyní pomocí tohoto skriptu můžeme spustit následující příkaz:

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

To vytvoří stejný řetězec jako spuštění ./hello <1.in :

Segmentation fault: 11

Nyní však můžete tento řetězec zachytit ze standardní chyby (stderr) a přenést jej do diff jak jste chtěli:

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

To vytváří přesný výstup, který byste dostali, kdyby byla chybová zpráva zapsána na standardní výstup, který jste původně očekávali:

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

Linux
  1. Jak přesměrovat výstup do souboru a Stdout v Linuxu

  2. Jak poslat Stdout do více příkazů?

  3. Jak přesměrovat výstup programu do souboru ZIP?

  1. Jak udělat program spustitelný odkudkoli?

  2. Jak přesměrovat Stderr a Stdout na různé soubory a také zobrazit v terminálu?

  3. Jak přesměrovat výstup do souboru a stdout

  1. Jak používat Nginx k přesměrování

  2. Jak získat MAC adresu vašeho stroje pomocí programu C?

  3. Jak ukončíte program X11 bez chyby