I'm using pax
to backup a directory over a ssh
link. If like to have a progress report saying how much of the transfer has occurred. With the -v
option, it'll output the filename that it's done to stderr
, so I figured I could get the count of how many files are in the directory and somehow pipe stderr
into my shell script and report how far it's gotten.
Thing is I'm not sure how to pipe stderr
without disrupting stdout
. It's running ksh
on the remote machine.
So this is what I have so far which will be run on the remote machine:
file_count=$(find "$target" -type f | wc -l)
count=0
progress() {
while [ $((++count)) -lt $file_count ]; do
echo -n "$((count * 100 / file_count))%\r" 1>&2
read
done
echo 100% 1>&2
}
# This line needs to be modified somehow so that
# stderr goes to progress while leaving stdout
# alone.
echo "$target" | pax -r -v | progress
Seems that even though read
says it supports -n
, it doesn't, so I can't read from a particular handle.
The general way to do this sort of thing in a Bourne shell is to temporarily redirect stdout to an auxiliary file descriptor. Something like:
{ cmd 2>&1 1>&3 | progress; } 3>&1
Here, the stdout of cmd
goes to the original stdout, while the stderr of cmd
goes to progress
. In your case, you should write:
{ echo "$target" | pax -r -v 2>&1 1>&3 | progress; } 3>&1
Note that any errors from echo
will not go into the pipe to progress
(which is probably fine, and probably what you want), and you may need to be concerned with buffering issues. Also note the double quotes on $target
. For robustness, you should probably use printf '%s\n' "$target"
rather than echo
.