Prepend, stdout and stderr command

I have the following code that reads several commands, prints them, and outputs their output.

while read line ; do echo "C:$line" echo "O:$(${line} 2>&1 | perl -pe 's,\n,\\n,'g)\n" done << EOF g++-4.8 -O2 -Wall -Wextra -pedantic -pthread main.cpp ./a.out EOF 

Output:

 C:g++-4.8 -O2 -Wall -Wextra -pedantic -pthread main.cpp O:main.cpp: In function 'int main(int, char**)':\nmain.cpp:3:9: warning: unused variable 'unused' [-Wunused-variable]\n int unused;\n ^\n\n C:./a.out O:*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff3bd01a5c ***\n======= Backtrace: =========\n/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f6960e1ab96]\n./a.out[0x400502]\n/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f6960dbd76d]\n./a.out[0x400535]\n======= Memory map: ========\n\n 

I would like to distinguish between stdout and stderr and use the prefix "E:" for stderr. I would also like to print the exit code of each command line.

How can i achieve this?

+4
source share
2 answers
 #!/bin/bash # Add a prefix to each line of stdin. prefix() { local line while read line; do printf '%s%s\n' "$1" "$line"; done } # Execute each command. Notice the `(' and `)' surrounding the loop body, which starts # a sub-shell for each iteration. Running in a sub-shell lets us use `trap EXIT' to # cleanup. while read command; do ( # Create FIFOs for the command stdout and stderr. stdout=$(mktemp -u) stderr=$(mktemp -u) mkfifo "$stdout" "$stderr" # Delete the FIFOs when this iteration of the loop finishes. Use `trap' to ensure # cleanup happens whether we finish normally or are signalled. trap 'rm -f "$stdout" "$stderr"' EXIT # Read from the FIFOs in the background, adding the desired prefixes. prefix 'O:' < "$stdout" >&1 & prefix 'E:' < "$stderr" >&2 & # Now execute the command, sending its stdout and stderr to the FIFOs. echo "C:$command" eval "$command" 1> "$stdout" 2> "$stderr" exitcode=$? # Wait for the `prefix' processes to finish, then print the exit code. wait echo "R:$exitcode" exit $exitcode ) done 
+9
source

Here is my view. I think he is doing something similar to John, but seems to have a few smaller lines. I just included it here as an alternative, as I had a similar problem and wanted to try to define a more compact solution.

I think the main culprit for this problem is that the pipe | does not allow you to specify a stream similar to how it is redirected, for example. 2> .

The solution I came up with is to combine the output of a number of subshells with the internal processing of stdout , and then redirect it to an alternate temporary stream 3 .

The next subshell redirects stderr to stdin again and repeats the activity of the inner shell (although the prefix is ​​with "E:" , not "O:" ). It redirects the output here to stdout again, although >&2 can be removed if you want to have everything in stdin (but I think keeping these streams separately is an advantage).

The outer shell joins the &3 thread again with stdin .

Since the two inner shells handle stdin and stdout separately (due to the alternative prefixes "O:" and "E:"), you need to run the perl command twice, so I wrapped it up in the fold function to maintain the order of things, and various things are also added here prefixes.

Perhaps you could end sed and include this in the perl regular expression, and also know that \\n is entered at the end of each line with your perl command. In fact, my personal opinion is that the linear folding introduced by this command should no longer be necessary, but I kept it for fidelity with your original problem.

 function fold { perl -pe 's,\n,\\n,'g | sed 's/^\(.*\)$/'${1}':\1\n/' } while read line ; do echo "C:$line" ( ( ${line} | fold O >&3 ) 2>&1 | fold E >&2 ) 3>&1 done 
+1
source

Source: https://habr.com/ru/post/1499828/


All Articles