3

Saving and restoring the cursor position should be possible with simple ANSI escape sequences

ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:

  • [...]
  • Save cursor position: \033[s
  • Restore cursor position: \033[u

Source: Bash Prompt HOWTO: Cursor movement

However, it seems that this ANSI sequences restore only the horizontal position of the cursor. For example:

$ printf 'Doing some task...\e[s\n\nMore text\n\e[udone!\n\n\n'
Doing some task...

More text
                  done!


$

where the done! is horizontally at the correct position but not vertically (correct in the sense of restored).

  1. Am I missing something, i.e. can you reproduce this?!
  2. Is this the intended desired behaviour? If so, how would I get the done! printed after the task...?
  3. If this should not happen, might this behaviour be triggered indirectly by something in my environment?

I searched and read the many questions about, but I did not find anything about this behaviour I experienced. Actually, the same occur with tput via

$ printf 'Doing some task...'; tput sc; printf '\n\nMore text\n'; tput rc; printf 'done!\n\n\n'
Axel Krypton
  • 324
  • 2
  • 12

2 Answers2

6

Am I missing something, i.e. can you reproduce this?!

I can, if I'm at the bottom of the terminal and the next line makes the content move up. But repeat the test in a terminal that doesn't scroll in the meantime. Hit Ctrl+L (or invoke clear) and start from the top. Then it behaves as you wish.

Is this the intended desired behaviour?

I think so. Cursor position is relative to the screen, not to its content.

How would I get the done! printed after the task...?

Possible approach: If you know you're going to print no more than 6 lines and the terminal is big enough, print 6 empty lines first so it scrolls first, then move the cursor up and only then print the meaningful text:

printf '\n\n\n\n\n\n'; printf '\033[6A'; printf 'Doing some task...\e[s\n\nMore text\n\e[udone!\n\n\n'

I used three separate printfs to show the logic, but it could be one.

Kamil Maciorowski
  • 19,242
  • 1
  • 50
  • 94
  • Nice catch with the scrolling down of the terminal, I had not thought about that. If this is an intended behaviour, and what you write makes sense, then your idea to avoid the scrolling down is easy and smart. – Axel Krypton Feb 04 '20 at 09:53
-1

Works for me. I prefer to use the terminfo database (man 5 terminfo) rather than hardcode escape sequences.

sc=$(tput sc) rc=$(tput rc) el=$(tput el)
clear; printf 'Doing some task...%s\n' "$sc"; sleep 1; printf '%sDONE%s\n' "$rc" "$el"

You can also move the cursor to an absolute position ({0,0} is top left), in case that's a better option than saving/restoring the current cursor position.

tput cup 4 40; sleep 1; printf "%s\n" 'This is row 4 column 40'
roaima
  • 107,089
  • 14
  • 139
  • 261
  • Doesn't work. The same issue if a terminal scrolled. – Artfaith Feb 28 '21 at 08:24
  • @F8ER this answer, like all the others, saves an absolute position on the screen. The absolute position doesn't change just because the text scrolled. – roaima Feb 28 '21 at 08:44
  • Of course, and that's why -1, sorry. This particular answer doesn't include anything explaining it and doesn't resolve the issue of the question. – Artfaith Feb 28 '21 at 08:56
  • Look at the edit histories. This answer offers clean terminfo rather then messy escape sequences. Both answers address the question, which (still) doesn't mention anything about tracking a position _relative_ to scrolled text – roaima Feb 28 '21 at 09:00