pipe multiple commands to less

If you want to move with :n and :p there is no other way but to run the commands, output the outputs to files, then less them:

svndiff () 
{
    d=$(mktemp -d /tmp/svndiffsXXXXX)
    for a in $(svn status | \grep ^M | sed 's/M       //');
    do
        svn diff "$a" > $(mktemp $d/diffXXXXX) 2>&1;
    done
    less "$d"/diff*
    rm -fr "$d"
}

(If you need them in order let me know and we can apply numbering.)

Otherwise, you could call a shell executing all of your commands, then pipe the concatenated output to less.


You could use process substitution:

less -f <(svn diff this) <(svn diff that)

But that's hard to use in a loop. Probably best to just use temporary files:

#!/bin/bash
dir=$(mktemp -d)
outfiles=()
IFS=$'\n'
set -f 
for file in $(svn status | \grep ^M | sed 's/M       //') ; do
    outfile=${file#.}             # remove leading dot (if any)
    outfile=${outfile//\//__}     # replace slashes (if any) with __
    svn diff "$file" > "$dir/$outfile";
    outfiles+=("$dir/$outfile")   # collect the filenames to an array
done
less "${outfiles[@]}"
rm -r "$dir"

The above tries to keep the filenames visible in the names of the temp files, with some cleanup for slashes and leading dots. (In case you get paths like ./foo/bar. I can't remember how svn outputs the file names, but anyway...)

The array is there to keep the order, though as @Kusalananda said, we could just do "$dir"/* instead, if the order doesn't matter. set -f and IFS=$'\n' in case someone creates file names with glob characters or white space.

Of course we could simplify the script a bit and create, say numbered temp files instead.


Using GNU Parallel you could do something like:

files=$(svn status | \grep ^M | sed 's/M       //' |
  parallel --files svn diff {})
less $files
rm $files

Tags:

Bash

Pipe

Less