Read selected text out-loud on Ubuntu Linux
Tags: linux, a11y
Published: 2021-05-13 03:29:15

---
title: Read selected text out-loud on Ubuntu Linux
published: true
description: 
tags: Linux, accessibility
//cover_image: https://direct_url_to_image.jpg
---

I'm bad at proofreading. I manage to gloss over most of my mistakes, no matter how many times I read something that I wrote.

Because of this, it was a godsend when I discovered that hitting the `alt` + `esc` keys on my Macbook would read the selected text out-loud ([Apple speak selection docs](https://support.apple.com/guide/mac-help/have-your-mac-speak-text-thats-on-the-screen-mh27448/mac)). I hear many of the mistakes I miss while proofreading. It's become an indispensable part of my writing workflow.

Unfortunately, my Linux machine doesn't have this feature built in, so I needed to hack it together.

## Building the read-selected-text script

If you have any experience using Apple's `alt` + `esc` text-to-speech feature, let me start by saying **this won't be nearly as good**. But, we can get something  that's _good enough_. 

Here's how it'll work:
* We'll create a script that runs when you hit `ctrl` + `esc`.
* The script will check to see if the text-to-speech application is already running. If it is, it will kill the process to stop the speech.
* If speech-to-text is not running, it will copy the text to the clipboard and pipe it into the text-to-speech application.

First, we're going to need to install a few packages:
* `xclip` and `xsel` help manage the clipboard for X11 desktops (Linux's standard windowing system).
* `espeak` reads text out-loud.

Run the following commands in your terminal:
```sh
sudo apt update
sudo apt install xclip xsel espeak
```

Next, make a `user-scripts` directory in your home folder, then navigate into that directory.

```sh
mkdir ~/user-scripts
cd ~/user-scripts
```

Next we're going to create a `read-selected-text` file, then set it as executable.

```sh
touch read-selected-text
chmod +x read-selected-text
```

Now, open the file with Nano by running `nano read-select-text`, and paste the following into the file:

```sh
#! /bin/bash

espeak_pid=$(pidof espeak)

# espeak argument reference:
# -a for volume. Max 200
# -p for pitch.  0 to 99, default is 50
# -v for voice

if [ -z "$espeak_pid"]
then
    xclip -out -selection primary | xclip -in -selection clipboard
    xsel --clipboard | tr "\n" " " | espeak -a 200 -p 60 -v english-us
else 
    kill $espeak_pid
fi
```

Press `ctrl` + `o` to save, then `ctrl` + `x` to exit Nano.

## Binding the script to a keyboard shorting

Open the **Settings** app, and navigate to **Keyboard** on the left-hand sidebar. At the bottom of this screen, click **Customize Shortcuts**, then scroll to the bottom and click **Custom Shortcuts**. Click the **Add Shortcut** button.

In the **name** field, title the shortcut "Read Selected Text."

In the **command** field, type the full path to the script we created earlier (my script's path is `/home/tyler/user-scripts/read-selected-text`). You can run the `pwd` command in your `user-scripts` directory to find your full path.

Set the shortcut. I set mine to `ctrl` + `esc`, but you can set yours to whatever you like.

Finally, click the **Add** button at the top of the window.

You can now test your screen reader. Select some text on your computer and run your shortcut. You should hear a robotic voice read the text back to you.

## Potential issues

X11 has been the default window system in Linux for decades, but distributions are starting to adopt Wayland. I haven't tested this script on a Wayland-based Ubuntu machine, but I suspect it might not work.

I also imagine this script will run into issues if two instances of espeak are ever running at the same time.

I built this as a minimal-effort script to get me up and running using information that I found on [Stack Exchange](https://askubuntu.com/questions/501910/how-to-text-to-speech-output-using-command-line) and [Ubuntu's documentation](https://help.ubuntu.com/community/TextToSpeech). If you have any improvements (or if you found parts of my instructions that are incorrect), please drop them in the comments below!