Search code examples
bashprintfecho

How to printf multiline output in place?


I'd like to print multiline output in place if it's posible. I have a simple for loop like this:

for i in {1..100}; do
  OUTP=`df -h |grep sda`
  echo -ne "$OUTP\r"
  sleep 5
done

I would like to get output:

/dev/sda2       110G  9.0G   96G   9% /mnt/sdb
/dev/sda1      1022M  248M  775M  25% /mnt/sdb/boot/efi

and to be replaced with new sizes, as I'm syncing files. but instead I'm getting:

/dev/sda2       110G   19G   87G  18% /mnt/sdb
/dev/sda2       110G   19G   86G  18% /mnt/sdb/boot/efi
/dev/sda2       110G   19G   86G  18% /mnt/sdb/boot/efi
/dev/sda2       110G   19G   86G  19% /mnt/sdb/boot/efi
/dev/sda2       110G   20G   85G  19% /mnt/sdb/boot/efi

It is jumping back only one line and replacing previous line, and keeps adding one line when there is only output of two lines. When output 3 lines it would add extra 2 lines like following:

/dev/sda2       110G   49G   56G  47% /mnt/sdb
/dev/sda1      1022M  248M  775M  25% /mnt/sdb/boot/efi
/dev/sda3       299G  949M  283G   1% /mnt/sdb/var
/dev/sda2       110G   49G   56G  47% /mnt/sdb
/dev/sda1      1022M  248M  775M  25% /mnt/sdb/boot/efi
/dev/sda3       299G  1.5G  282G   1% /mnt/sdb/var
/dev/sda2       110G   49G   56G  47% /mnt/sdb
/dev/sda1      1022M  248M  775M  25% /mnt/sdb/boot/efi
/dev/sda3       299G  1.9G  282G   1% /mnt/sdb/var
/dev/sda2       110G   49G   56G  47% /mnt/sdb
/dev/sda1      1022M  248M  775M  25% /mnt/sdb/boot/efi
/dev/sda3       299G  2.4G  281G   1% /mnt/sdb/var

And so on.
I tried \r\r but no luck. Any suggestions?


Solution

  • There are different terminal command sequences for that sort of thing. You might be able to save the cursor position and restore it with:

    $ tput sc; printf 'multi\nline\noutput\n'; tput rc; printf '%s' 'overwrite line 1'; echo; echo; echo
    overwrite line 1
    line
    output
    

    For your case, that becomes:

    tput sc     # Save cursor position
    for i in {1..100}; do
      outp=$(df -h |grep sda)
      printf '%s' "$outp"
      tput rc   # Restore cursor position
    done
    

    Note that it is bad practice to use ALL_CAPS for variable names, and also that the variable here is totally unnecessary (unless you wish to retain the data for use later in the script). You could easily do:

    for i ...; do
      tput sc
      df -h | grep sda
      tput rc
    done