This is a kind of hacky/unusual answer, the fact being that this is most likely possible in a not very clean way.
grep
itself seems to only print output when it encounters a newline character, your progress bar likely does not introduce a newline character when it updates, hence your issue.
strace
is a tool used to view the system calls that a command is calling, this includes things like reading and writing things to memory/storage, as well as things like opening/closing file descriptors.
With strace
you can view what a process is accessing, in the case of your pipe stout
is being passed to grep
, so with strace
you can view the text that's being fed to grep
. strace
will regularly be sent the output coming from the piped command, and you can sniff that output and display it. I was testing with rsync --progress
, which seems to run into a similar scenario. I used grep
on the ##%
because that's what rsync
uses to show progress.
rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%"
If you run this command you'll find that strace
doesn't have nice output, but that when I used it strace
caught a couple of read
s from the rsync
that grep
would not normally write
, showing read
s for 0%, 21%, 45%, 68%, 91% and 100%, seemed to update about every second (probably based on how often rsync
updates the progress).
So with that you can grep
the strace
output, which is not very nice, by calling the same grep
again.
rsync --progress file1 file2 | strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[0-9]*%"
The 2>&1
is important because strace
prints on stderr
. The > /dev/null
redirects stdout
to /dev/null
to prevent the output of the first grep
being reported. The end result of this was the following output:
0%
21%
45%
68%
91%
100%
You'll have to swap out the grep
, but it seems like it'll do the trick. It's not pretty, but it functions, and works around the restrictions of grep
. Seems like a grep -f
that works like tail -f
would be handy (I know grep -f
is already in use).
The first grep
is mostly just to filter down the text that strace
will be read
ing, since only the matching lines will be listed in strace
s read
calls, but you also need something for the text to be moving through so strace
can watch it.
Maybe, but I think it's going to be harder than you expect.
You can make the cursor move around the terminal by outputting ANSI control codes. For more on them, see here.
In principle, you could move the cursor to your progress bar, add an =
, and then move it back to wherever you plan to print output. Then on the next =
you'd have to do it again... but this would probably be ugly.
If you're willing to depart from bash, you can probably find libraries that make this kind of thing easier (like this).
Best Answer
You can build a patched cp and mv which then both support the -g switch to show progress. There are instructions and patches at this page. However: The page instructs you to do
which overwrites the original cp and mv. This has two disadvantages: Firstly, if an updated coreutils package arrives at your system, they are overwritten. Secondly, if the patched version has a problem, they might break scripts relying on standard cp and mv. I would rather do something like this:
which copies the files to /usr/local/bin which is intended for user compiled programs and gives them a different name. So when you want a progress bar, you say
mvg -g bigfile /mnt/backup
and use mv normally.Also you can do
alias mvg="/usr/local/mvg -g"
then you only need to saymvg bigfile /mnt/backup
and directly get the progress bar.