OBSERVAÇÃO: substituí hello.o
por hello
, pois a extensão do arquivo .o
nesse contexto normalmente indica um arquivo objeto e não o programa executável final.
De acordo com sua postagem, você quer executar o comando:
./hello <1.in 2>&1 | diff - 1.out
E você deseja que a mensagem de erro execute ./hello <1.in
para aparecer na saída deste comando. No entanto, a mensagem de erro não vem do programa hello.o
, mas do shell. A coisa mais próxima que posso imaginar para aproximar o efeito desejado com uma única linha é executar o comando em um subshell e usar essa saída com o comando diff
:
2>&1 bash -c './hello <1.in' | diff - 1.out
Isso nos dá a seguinte saída:
1c1,6
< bash: line 1: 58469 Segmentation fault: 11 ./hello < 1.in
---
> 3
> 9
> 20
> 4
> 5
> 11
A única diferença é que, nesse caso, você obtém alguns metadados adicionais gerados pelo shell (ou seja, o número da linha e a cadeia de caracteres do comando). Se você quiser replicar exatamente a mensagem de erro, use trap
para inserir um gancho que imprima exatamente a seqüência correta.
Não consegui encontrar uma maneira de extrair a mensagem de erro por meio de programação. Fui ao código fonte Bash e pesquisei para a mensagem "Falha de segmentação". Eu encontrei em um arquivo chamado siglist.c , juntamente com um monte de outros sinais e erros descrições. Usando essa informação eu escrevi o seguinte 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}"
Agora, usando esse script, podemos executar o seguinte comando:
(trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in)
Isso produz a mesma string que está executando ./hello <1.in
:
Segmentation fault: 11
Mas agora você pode capturar essa string do erro padrão (stderr) e canalizá-la para diff
da maneira que você queria:
(2>&1 trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in) | diff - 1.out
Isso produz a saída exata que você teria obtido se a mensagem de erro tivesse sido gravada na saída padrão que você esperava originalmente:
1c1,6
< Segmentation fault: 11
---
> 3
> 9
> 20
> 4
> 5
> 11