1. Overview

In this tutorial, we’ll explore various ways to add a clock to shell prompts. We’ll begin with Bash and implement a basic clock that updates interactively. Next, we’ll write a simple Bash script that renders a live clock inside the terminal.

In addition to Bash, we’ll also learn how to create a live clock for the Zsh prompt without relying on any external plugins. Finally, we’ll provide a couple of generic solutions that should apply to most shells.

2. Bash

By default, the Bash shell prompt displays the username, hostname, and current directory:

user@baeldung:~$

Usually, the prompt is set with the PS1 environment variable:

$ echo $PS1
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$

2.1. Basic Clock for the Prompt

Let’s update this environment variable to show the current time:

$ PS1='\[\u@\h:\T:\w\$'

Let’s break this down:

  • \u displays the username
  • @ is printed literally, which separates the username and the hostname
  • \h displays the hostname
  • \T displays the current time in a 24-hour format
  • \w prints out the working directory

Once we set the prompt, it now displays a clock:

baeldung@baeldung:09:56:50:~$

However, we should know that the clock updates only when we press the Return key:

baeldung@baeldung:10:01:01:~$^C
baeldung@baeldung:10:01:07:~$^C
baeldung@baeldung:10:01:08:~$^C
baeldung@baeldung:10:01:09:~$^C

Alternatively, it also updates when we send SIGINT (interrupt signal) through Ctrl+C.

2.2. Real-Time Clock

Nevertheless, if we prefer a real live clock, we can write our own using tput and date:

while sleep 1;
  do tput sc;
  tput cup 0 $(($(tput cols)-11));
  echo -e "\e[32m`date +%r`\e[39m";
  tput rc;
done &

Let’s dig into this:

  • while sleep 1 runs the code indefinitely with a second pause for each iteration
  • tput sc stores the current cursor position and attributes
  • tput cup sets the cursor position where:
    • 0 is the row number
    • $(tput cols)-11 is the column number that is 11 columns from the right
  • echo -e prints the text with escape sequences:
    • \e[32m sets the color to green for time text
    • date +%r displays the current time in a 12-hour format
    • \e[39m resets the color text to default
  • tput rc restores the cursor attributes that were stored previously

Here’s the clock:

Now, if we want this to persist across the shell sessions, we can simply put this in ~/.bashrc:

$ echo 'while sleep 1; do tput sc; tput cup 0 $(($(tput cols)-11)); echo -e "\e[32m`date +%r`\e[39m"; tput rc; done &' >> ~/.bashrc

3. Zsh

By default, Zsh provides a lot of flexibility. In addition to the available options, there are many plugins written for different purposes. However, for our use case, we’ll implement the clock manually.

3.1. zle

In Zsh, there is a built-in command zle (Zsh line editor). It lets us customize the behavior of the prompt via custom keymappings, functions, and widgets.

Additionally, we can use it with the reset-prompt argument, which forces the prompt to re-evaluate and re-render the edit buffer. In other words, zle reset-prompt updates and refreshes the prompt to render dynamic content.

3.2. Configuring Live Clock

The config file for the interactive shell is ~/.zshrc. So, let’s add the config for the live clock here:

...
setopt PROMPT_SUBST
PROMPT='%B%F{red}%n@%m%f%F{yellow}[%D{%L:%M:%S}]%f:%F{blue}${${(%):-%~}}%f$ %b'

TMOUT=1
TRAPALRM() {
    zle reset-prompt
}

Let’s explore what happens here:

  • setopt PROMPT_SUBST allows command substitution to display dynamic contents in the shell prompt
  • PROMPT lets us customize how the shell prompt looks:
    • %B% makes the text bold
    • F{red} sets the text color to red
    • %n displays a username
    • %@ prints the current time in a 12-hour format
    • %m displays hostname
    • %f resets the text color
    • %f%F{yellow} sets the text color to yellow
    • [%D{%L:%M:%S}] displays the time in [hh:mm:ss] format
    • %F{blue} sets the text color to blue
    • ${${(%):-%~}} displays and format the current working directory
  • TMOUT=1 sets the idle timeout of the shell to 1 second, which invokes TRAPALRM
  • TRAPALRM is invoked every $TMOUT second to reset and redisplay the prompt

In summary, the code creates a prompt that contains the current time and updates it every second. When we put this code inside the config file and restart the shell session, it displays a clock in the prompt:

4. Generic Solutions

In this section, we expand on methods that should work on all shells.

4.1. watch, date, and figlet

Alternatively, if we just want to display a live clock in the terminal and nothing else, we can use this command:

$ watch -t -n1 "date +%T|figlet"

Let’s dissect this:

  • watch periodically executes a command or a script
  • -t lets watch interpret ANSI colors and formatting codes
  • -n1 specifies the interval, which is 1 second
  • “date +%T | figlet” outputs the current time in hh:mm:ss format via figlet

Here’s how it looks:

Current Time via figlet

4.2. tmux

Fortunately, tmux doesn’t need any work. By default, it displays the current time in the status bar:

tmux

However, if we want to remove the date, then we simply add this line to ~/tmux.conf:

status-right " "#{=21:pane_title}" %H:%M"

5. Conclusion

In this article, we learned how we can customize a shell to display a live clock. We delved into the details of implementing it for both Bash and Zsh shells.

In addition, we also discussed how to display a live clock that works on most shells and terminals.

Comments are closed on this article!