The following function run_indented runs the passed command line and indents the standard outputs STDOUT and STDERR with $INDENT (default: ):
run_indented() {
local indent=${INDENT:-" "}
{ "$@" 2> >(sed "s/^/$indent/g" >&2); } | sed "s/^/$indent/g"
}
Example with default indent:
run_indented bash <<'EOF'
echo "foo" >&2
echo "bar"
EOF
Prints:
foo
bar
Example with custom and nested indent:
export -f run_indented
INDENT='- ' run_indented bash <<'EOF'
echo "foo" >&2
echo "bar"
# The following run_indented only works if
# it was exported as in the first line.
run_indented bash -c '
echo "foo2" >&2
echo "bar2"
'
EOF
Prints:
- bar
- foo
- - foo2
- - bar2
Bonus: Keeping the formatting
Some tools check if they are attached to a terminal and only output formatting / colors, if that's the case.
Indentation solutions based on piping will likely cause the indented tool to not see a terminal, and your colors are gone.
If you want to keep the formatting, try the following version:
run_indented() {
local indent=${INDENT:-" "}
local indent_cmdline=(awk '{print "'"$indent"'" $0}')
if [ -t 1 ] && command -v unbuffer >/dev/null 2>&1; then
{ unbuffer "$@" 2> >("${indent_cmdline[@]}" >&2); } | "${indent_cmdline[@]}"
else
{ "$@" 2> >("${indent_cmdline[@]}" >&2); } | "${indent_cmdline[@]}"
fi
}
This version attempts to make your invoked command see a terminal if there actually is one. That is, no matter if your script is part of a pipe or not, it should behave as expected.
Yet, the function can't guarantee the indentation, because prefixing each lines with spaces doesn't stop carriage returns (\r) from jumping back to the start of the line. Also there's a plethora of ways to move the cursor ahead of the indentation.
If it's only for the visuals, the DEC Private Mode Set (DECSET) with the Set Left and Right Margins (DECSLRM) function would be perfect to actually increase the terminals left margin. Unfortunately—at least when I tested it—changing to and back from that mode clears the screen so that you won't be able to see the indented output.