Linux Command to Output Each Line Forward and Backwards

bashio-redirectionlinuxzsh

I'm looking for a "meta-command" xyz such that:

(echo "foo"; echo "bar") | xyz rev

will return:

foo oof
bar rab

I'd like to avoid temporary files, i.e. I'm looking for a solution neater than:

tempfile=$(mktemp)
cat > $tempfile
cat $tempfile | rev | paste $tempfile -

(And of course I want a general solution, for any command, not just rev, you can assume that the command outputs exactly one line for each input line.)

Zsh solution would be also acceptable.

Best Answer

There will be a lot of problems in most cases due to the way that stdio buffering works. A work around for linux might be to use the stdbuf program and run the command with coproc, so you can explicitly control the interleaving of the output.

The following assumes that the command will output one line after each line of input.

#!/bin/bash
coproc stdbuf -i0 -o0 "$@"
IFS=
while read -r in ; do
    printf "%s " "$in"
    printf "%s\n" "$in" >&${COPROC[1]}
    read -r out <&${COPROC[0]}
    printf "%s\n" "$out"
done

If a more general solution is needed as the OP only required each line of input to the program to eventually output one line rather than immediately, then a more complicated approach is needed. Create an event loop using read -t 0 to try and read from stdin and the co-process, if you have the same "line number" for both then output, otherwise store the line. To avoid using 100% of the cpu if in any round of the event loop neither was ready, then introduce a small delay before running the event loop again. There are additional complications if the process outputs partial lines, these need to be buffered.

If this more general solution is needed, I would write this using expect as it already has good support for handling pattern matching on multiple input streams. However this is not a bash/zsh solution.

Related Question