Piping STDERR vs. STDOUT

I don't know what text your book uses, but the bash manual is clear (if you're a little familiar with redirections already):

If |& is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.

So if you don't want to mix standard output and standard error, you'll have to redirect standard output somewhere else. See How to grep standard error stream (stderr)?

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

Both fd 1 and 3 of script.sh and sed will point to the original stdout destination however. If you want to be a good citizen, you can close those fd 3 which those commands don't need:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bash and ksh93 can condense the >&3 3>&- to >&3- (fd move).


|& pipes stderr to stdin, like 2>&1 |, so the next program will get both on stdin.

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.

|& in bash is just a (not terribly portable) shortcut for 2>&1 |, so you should see every line indented.