Saturday, 14 March 2026

Moving the cursor using printf

Controlling the Cursor in Bash Using ANSI Escape Codes 🖥️

When working with terminal applications or interactive shell scripts, it is sometimes useful to control where text appears on the screen.

Using ANSI escape sequences, Bash scripts can:

  • Move the cursor

  • Save and restore cursor position

  • Build interactive terminal tools

  • Create dynamic dashboards

  • This article explains the most useful cursor movement commands in Bash and demonstrates a simple script that moves the cursor, prints text, and restores the cursor position.

1️⃣ Useful Cursor Commands for Bash

ANSI escape codes allow you to control the cursor position inside the terminal.

CodeMeaning
\e[HMove cursor to top-left corner
\e[10;10HMove cursor to row 10, column 10
\e[AMove cursor up
\e[BMove cursor down
\e[CMove cursor right
\e[DMove cursor left
\e[7Save cursor position
\e[8Restore cursor position

These codes are interpreted by the terminal when printed using commands such as printf.


2️⃣ Example Bash Script: Moving the Cursor

Below is a simple script demonstrating how to:

  • Save the cursor position

  • Move the cursor to another location

  • Print text

  • Restore the cursor

Your original script:

[root@oel01db Shell-Scripting]# cat 01-Move-Cursor.sh

#!/usr/bin/env bash

# save the cursor position
printf '\e7'

# jump somewhere
printf '\e[20;20H'

# print "hello world"
printf 'Hello World'

# restore the cursor
printf '\e8'

[root@oel01db ShellHello World#




























3️⃣ How the Script Works

Let's break down each step.


Step 1 — Save the Cursor Position

printf '\e7'

This command saves the current cursor position.

The terminal remembers where the cursor is located so it can be restored later.

This is useful when you temporarily move the cursor somewhere else but want to return to the original position afterward.


Step 2 — Move the Cursor

printf '\e[20;20H'

This ANSI escape sequence moves the cursor to:

Row 20
Column 20

Structure of the command:

\e[<row>;<column>H

So in this example:

\e[20;20H

means:

👉 Move the cursor to line 20, column 20.


Step 3 — Print Text

printf 'Hello World'

Since the cursor was moved to position 20,20, the text appears exactly at that location on the terminal screen.


Step 4 — Restore the Cursor

printf '\e8'

This restores the cursor to the previous saved position.

As a result, the script briefly moves the cursor to another location, prints the message, and then returns to the original position.



4️⃣ Alternative Save and Restore Codes

Some terminals support a slightly different syntax:

CommandMeaning
\e[sSave cursor position
\e[uRestore cursor position

Example:

printf '\e[s'
printf '\e[10;10H'
printf 'Hello'
printf '\e[u'

These are considered more portable across different terminal emulators.


5️⃣ Clearing the Screen

Many terminal programs also combine cursor movement with screen control.

For example:

\e[2J

This clears the entire terminal screen.

Example:

printf '\e[2J'
printf '\e[H'

Meaning:

  1. Clear screen

  2. Move cursor to the top

This is commonly used in terminal dashboards.


6️⃣ Practical Uses of Cursor Movement

Cursor control is extremely useful when building interactive terminal programs.

Examples include:

Terminal dashboards

Updating values without scrolling.

Example:

CPU Usage: 30%
Memory Usage: 50%
Disk Usage: 70%

The script updates numbers in place.


Progress bars

Example:

Downloading: [##########------] 50%

The cursor moves back and updates the same line.


Interactive CLI tools

Tools like:

  • htop

  • top

  • watch

  • ncurses applications

all rely heavily on cursor positioning.


7️⃣ Best Practice: Use printf Instead of echo

When printing ANSI escape sequences, it is better to use printf instead of echo.

Reason:

echo behavior can vary between shells, while printf handles escape sequences more reliably.

Example:

printf '\e[10;10HHello'

8️⃣ Quick Demo Script

Here is a simple script that demonstrates cursor movement:

#!/usr/bin/env bash

printf '\e[2J' # clear screen
printf '\e[5;10HHello'
printf '\e[7;10HWorld'
printf '\e[10;10HDone'

Output will appear at different positions on the terminal screen.


4️⃣ Moving the Cursor Using tput

Instead of using raw ANSI escape sequences, you can use the tput command.

tput interacts with the terminfo database, which describes the capabilities of the current terminal.

This makes scripts more portable across different terminal types.

Your script using tput:

[root@oel01db Shell-Scripting]# cat o1-Move-Cursor-Using-tput.sh
#!/usr/bin/env bash

# Save the cursor position
tput sc

# Move cursor to Row 20, Column 20
# Note: tput uses 0-based indexing (0 0 is top-left)
tput cup 20 20

# Print the text
printf 'Hello World'

# Restore the cursor position
tput rc
[root@oel01db Shell-Scripting]#

5️⃣ How the tput Script Works

Save Cursor Position

tput sc

sc means Save Cursor.


Move Cursor

tput cup 20 20

cup means Cursor Position.

Syntax:

tput cup ROW COLUMN

Important difference:

tput uses 0-based indexing.

So:

0 0

is the top-left corner of the terminal.


Print Text

printf 'Hello World'

The text appears at the cursor location.


Restore Cursor

tput rc

rc means Restore Cursor.

This moves the cursor back to the previously saved position.


6️⃣ Comparison: ANSI Escape Codes vs tput

FeatureANSI Escape Codestput
SpeedSlightly fasterSlightly slower
PortabilityDepends on terminal supportHighly portable
ReadabilityHarder to readEasier to understand
DependenciesNo external commandRequires tput
CompatibilityWorks on most modern terminalsWorks across many terminal types

Example comparison:

ANSI version

printf '\e[20;20H'

tput version

tput cup 20 20

Both perform the same task, but tput is usually more portable.

6️⃣ An example for progress bar is given below.

 #!/usr/bin/env bash

# Define colors and styles

BLUE=$(tput setaf 4)

GREEN=$(tput setaf 2)

RESET=$(tput sgr0)

BOLD=$(tput bold)

# Hide the cursor so it doesn't flicker

tput civis

# Function to draw the bar

draw_bar() {

    local percentage=$1

    local width=20

    # Calculate how many # to draw (percentage * width / 100)

    local filled=$(( percentage * width / 100 ))

    local empty=$(( width - filled ))

    # Prepare the bar string

    # printf -v allows saving the output to a variable

    printf -v bar_filled "%${filled}s" ""

    printf -v bar_empty "%${empty}s" ""

    # \r moves cursor to the start of the line

    # Use ${bar_filled// /#} to replace spaces with #

    # Use ${bar_empty// /-} to replace spaces with -

    printf "\r${BOLD}Downloading: ${RESET}[${BLUE}${bar_filled// /#}${RESET}${bar_empty// /-}] ${GREEN}%3d%%${RESET}" "$percentage"

}

# Simulation Loop

for i in {0..100..5}; do

    draw_bar "$i"

    sleep 0.2

done

# Show the cursor again and move to a new line

tput cnorm

echo -e "\nDownload Complete!"

No comments:

Post a Comment

JFrog Artifactory - How to install

JFrog Artifactory OSS Installation Guide CentOS 9 + PostgreSQL 17 This guide provides a structured workflow to install JFrog Artifactory OSS...