grub2-mkconfig
normally writes the generated config file to
stdout so you can redirect it conveniently. Status information
is written to stderr since it would interfere with the
redirected output. When you use the -o
argument instead, the
latter behavior stays the same, which it should for sake of
consistency:
# grub2-mkconfig >/tmp/grub.conf.a
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-4.8.15-200.fc22.x86_64
Found initrd image: /boot/initramfs-4.8.15-200.fc22.x86_64.img
Found linux image: /boot/vmlinuz-4.4.14-200.fc22.x86_64
Found initrd image: /boot/initramfs-4.4.14-200.fc22.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-b764638bab7b90d16d0510c14a429d80
Found initrd image: /boot/initramfs-0-rescue-b764638bab7b90d16d0510c14a429d80.img
Found Fedora release 22 (Twenty Two) on /dev/sda2
done
# grub2-mkconfig -o /tmp/grub.conf.b
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-4.8.15-200.fc22.x86_64
Found initrd image: /boot/initramfs-4.8.15-200.fc22.x86_64.img
Found linux image: /boot/vmlinuz-4.4.14-200.fc22.x86_64
Found initrd image: /boot/initramfs-4.4.14-200.fc22.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-b764638bab7b90d16d0510c14a429d80
Found initrd image: /boot/initramfs-0-rescue-b764638bab7b90d16d0510c14a429d80.img
Found Fedora release 22 (Twenty Two) on /dev/sda2
done
# diff -u /tmp/grub.conf.{a,b}
NOTE: I've replaced hello.o
with hello
, since the .o
file extension in this context would typically denote an object file and not the final executable program.
According to your post, you want to run the command:
./hello <1.in 2>&1 | diff - 1.out
And you want the error message from running ./hello <1.in
to appear in the output of this command. However the error message isn't coming from the hello.o
program itself, but from the shell. The closest thing I can think of for approximating the desired effect with a single line is to run the command in a subshell and then use this output with your diff
command:
2>&1 bash -c './hello <1.in' | diff - 1.out
This gives us the following output:
1c1,6
< bash: line 1: 58469 Segmentation fault: 11 ./hello < 1.in
---
> 3
> 9
> 20
> 4
> 5
> 11
The only difference is that in this case you get some additional metadata output by the shell (i.e. the line number and the command string). If you want to exactly replicate the error message, then you can use trap
to insert a hook which prints out exactly the right string.
I couldn't find a way to programmatically extract the error message, so I went to the Bash source code and searched for the "Segmentation fault" message. I found it in a file called siglist.c, along with a bunch of other signals and error descriptions. Using that information I wrote the following 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}"
Now, using this script, we can run the following command:
(trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in)
This produces the same string as running ./hello <1.in
:
Segmentation fault: 11
But now you can capture that string from standard error (stderr) and pipe it to diff
like you wanted:
(2>&1 trap 'bash trapdesc.sh $?' EXIT; ./hello <1.in) | diff - 1.out
This produces the exact output that you would have gotten if the error message had been written to standard output you had originally expected:
1c1,6
< Segmentation fault: 11
---
> 3
> 9
> 20
> 4
> 5
> 11
Best Answer
Your first try was correct;
2>filename
is how you redirect stderr. It may be the case that your program is writing some non-errors to stderr, or the java program is running other programs that output to stderr.