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.
| Code | Meaning |
|---|---|
\e[H | Move cursor to top-left corner |
\e[10;10H | Move cursor to row 10, column 10 |
\e[A | Move cursor up |
\e[B | Move cursor down |
\e[C | Move cursor right |
\e[D | Move cursor left |
\e[7 | Save cursor position |
\e[8 | Restore 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:
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:
| Command | Meaning |
|---|---|
\e[s | Save cursor position |
\e[u | Restore 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:
-
Clear screen
-
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 -
ncursesapplications
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
| Feature | ANSI Escape Codes | tput |
|---|---|---|
| Speed | Slightly faster | Slightly slower |
| Portability | Depends on terminal support | Highly portable |
| Readability | Harder to read | Easier to understand |
| Dependencies | No external command | Requires tput |
| Compatibility | Works on most modern terminals | Works 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