19 Sep 2013 eMBee   » (Journeyer)

watch for the fish shell

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?

However, 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:

while true
  clear
  du -h (ls -tr) | tail -20 | cut -c -(math $COLUMNS - 5)
  sleep 2
end

Unfortunately using 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/^/'\e'\[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/^/'\e'\[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 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.

Syndicated 2013-09-19 05:44:43 (Updated 2013-09-19 07:11:05) from DevLog

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!