5

Here I want something like the way aircrack-ng does to display text in the terminal screen, or like matrix scripts ... !

For example, if my terminal screen already contains 4 lines, I want to update the 1st of those first lines in its place, and same for other lines ... (using bash)

To be more precise, I want a script like the following:

#!/bin/bash
while :
  do
    echo "line1"
    echo "line2"
    echo "line3"
    echo "line4"
    # without using clear cmd, next cycle line1 should be printed
    # in line1 place not in a new line , and same for other lines
  done
Yunus
  • 1,684
  • 1
    man terminfo will give you cursor movement operations, which can be implement via the tput command. For example tput home. The interesting ones include "remember my current (x,y) position" and "return to the remembered position". If I could remember what they were I'd write a full answer. – Chris Davies Nov 10 '15 at 15:57

2 Answers2

14

On terminals that support it, you can use tput sc to save the cursor position and tput rc to restore it:

i=0
tput sc
while sleep 1; do
  tput rc
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
done

output

You can save those escape sequences in a variable to avoid having to invoke tput every time:

rc=$(tput rc) ||
  echo >&2 "Warning: terminal doesn't support restoring the cursor"
...
printf '%s\n' "${rc}line1..."

On the rare terminals that don't support it, you can always use cursor positioning sequences,

while sleep 1; do
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
  echo "line$((i=i+1))"
  tput cuu 4 # or up=$(tput cuu1); printf %s "$up$up$up$up"
done

See the terminfo man page in section 5 (if your system ships with ncurses) for more details.

7

I answered this on StackOverflow a few months ago, see Overwriting last terminal output(multiple lines). While I suppose it is possible that OP meant to print literally "line1", "line2", etc., that would only be of interest in a classroom exercise. Real programs print more interesting things, so I am answering that question. As before, the current q/a overlooks the problem when updated lines are shorter than the existing line. Addressing that

#!/bin/bash
tput sc
while :
  do
    tput rc
    echo "line1"; tput el
    echo "line2"; tput el
    echo "line3"; tput el
    echo "line4"; tput el
    # without using clear cmd, next cycle line1 should be printed
    # in line1 place not in a new line , and same for other lines
  done

Agreeing that cuu is a good alternative, using grep to check the availability of a capability seems less effective than using tput itself, e.g.,

restore=$(tput sc)
[[ -z "$restore" ]] && restore=$(tput cuu 4)
[[ -z "$restore" ]] && restore=$(tput cuu1; tput cuu1; tput cuu1; tput cuu1)

which is still a little crude in the way the number of lines is embedded in the expressions. But then you could just execute $restore at the end of the loop.

Something similar could be done with the check for el in the terminal.

Given that this is bash, the echo "line1", etc., should really be a function (which would eliminate the redundant tput el calls).

All of these capabilities are likely to be supported with terminals that OP is likely to encounter. The save/restore cursor controls are a weak point, since there are two main variants:

  • DECSC/DECRC (supported by xterm - see XTerm Control Sequences):

    ESC 7     Save Cursor (DECSC).
    ESC 8     Restore Cursor (DECRC).
    
  • ANSI.SYS (also supported by xterm, but not by all "xterm emulators"):

    CSI s     Save cursor (ANSI.SYS), available only when DECLRMM is disabled.
    CSI u     Restore cursor (ANSI.SYS).
    

Other useful sources of information:

The question, by the way, is mis-titled, since the example given (and so far none of the answers) uses scrolling. One could (again referring to terminfo, and limiting oneself to VT100-like terminals such as xterm) use scrolling regions. The place to start would be here (from the terminfo manual page):

   change_scroll_region          csr        cs        change region to      
                                                      line #1 to line #2    
                                                      (P)   
Thomas Dickey
  • 76,765
  • thomas - re my edit: one answer in which i used a lot of nested codeblocks is here. i only mention it because i used to resort to those back-quoted strings in (un)?ordered lists here, too, until i learned the other way was possible. you just need to factor the indentation. – mikeserv Nov 10 '15 at 22:50