The following command is used to watch the progress of files being updated in a directory.
watch 'du -h *| tail -20 | cut -c -$(($COLUMNS-5))'
cut is used so we don't get linewraps in the output. And we need to subtract 5 from the width because there is a tabstop in there which
cut counts as 1 instead of the width of the tabstop (which is 8 minus the width of the size column)
This command works fine as long as files are updated in alphabetical order, but when this is not the case we need to sort files by time.
We need to do something like this instead:
watch 'du -h $(ls -tr)| tail -20 | cut -c -$(($COLUMNS-5))'
Unfortunately this only works if the filenames don't contain spaces.
fish handles spaces in filenames just fine:
du -h (ls -tr)| tail -20 | cut -c -(math $COLUMNS - 5)
So instead of trying to find a solution for dealing with spaces in bash, lets just use a better shell, shall we?
watch insists on executing the command with
sh -c, so we need to devise our own watch loop for
fish instead. That's not really hard:
du -h (ls -tr) | tail -20 | cut -c -(math $COLUMNS - 5)
clear causes an annoying flicker, especially if the
du command takes a bit longer.
ANSI escape-sequences help:
clear while true echo \e\[H du -h (ls -tr) | tail -20 | cut -c -(math $COLUMNS - 5) sleep 2 end
This causes the cursor to be moved into the top-left corner without clearing the screen.
Now we are almost there. Two problems still:
The tab character used to align the columns does not overwrite anything in its space. Likewise at the end of the line, if the newly written line is shorter then the remaining part of the old line is not cleared.
We can fix this with some
sed trickery to clear the path:
clear while true echo \e\[H du -h (ls -tr) | tail -20 | sed -e 's/^/\x1b\[K/' | cut -c -(math $COLUMNS - 2) sleep 2 end
The ANSI escape sequence
ESC[K clears the line just before it is rewritten.
This has almost the same effect as clearing the screen, but without the flicker because we only start clearing after
du has done its work.
And because the escape sequence adds 3 characters to the output we need to adjust the width accordingly.
At the end we can also add a command to clear the rest of the screen.
Leaves one last issue:
$COLUMNS doesn't get updated if the terminal is resized. Granted, it's a nit-pick really, because how often does one resize the terminal. But to make this command generally usable, let's fix this too:
clear while true echo \e\[H du -h (ls -tr) | tail -20 | sed -e 's/^/\x1b\[K/' | cut -c -(math (tput cols) - 2) echo \e\[0J sleep 2 end
This is now pretty usable, so we'll leave it at that. There is still some room for improvement though. For example we could make the line-count flexible based on the terminal height. Also currently we are estimating that the size column is at least 2 characters wide so the tabstop adds at most 5 characters worth of space which cut does not count. Should it be less then we would get a linewrap again and if it is more then we get empty space at the end of the line.
cut likely also has problems with multibyte unicode characters. This can probably be solved by switching the terminal in a no-wrap mode while the command is running, or finding a replacement for
cut that handles these issues.
For those who prefer to stick with sh, i found a way how do deal with spaces:
watch 'ls -tr | while IFS= read -r i; do du -h "$i"; done | tail -20 | cut -c -$(($COLUMNS-5))'