This is more of a proof of concept, that you can use rtl_fm and redsea programs, to read RDS data and also listen the audio! I don't think, that many people will prefer this way to listen to radio stations :)
So, first install rtl_fm, by installing the package rtl-sdr. In Debian/Ubuntu systems use this command: sudo apt install rtl-sdr.
Then you have to install redsea, which is a command line program to parse RDS data, from rtl_fm data. Go to its Github repo and follow the instructions: https://github.com/windytan/redsea
Now you can use the script below to listen to your favorite radio station and also read any RDS text, at the same time, on the terminal!
You can and must configure the rtl_fm command line in the script, to match your system setup, as any RTLSDR device is different and needs different parameters, specially the PPM value.
And a small preview, nothing much...

Da script...
#!/bin/bash
#title : rds.sh
#description : Listen to radio and read RDS data, with rtl_fm and redsea
#author : xqtr // cp737.net
#date : 2025/11/04
#version : 1.0
#usage : sdr.sh <freq> // sdr.sh 103.5
#notes : Install rtl_dm and redsea // https://github.com/windytan/redsea
# Initialize variables
last_prog_type=""
last_partial_radiotext=""
last_partial_ps=""
if [ "$#" -ne 1 ]; then
echo ""
echo "Usage:"
echo " rds.sh <freq>"
echo ""
echo "Example:"
echo " rds.sh 103.5"
echo ""
exit 1
fi
clear
echo -e "\033[4;1H\033[2KPress Ctrl+C to stop"
# Use tee to split the rtl_fm output to both audio player and redsea
# Redirect rtl_fm stderr to /dev/null to hide startup messages
rtl_fm -M fm -l 0 -A std -p 0 -s 171k -g 20 -F 9 -f "$1"M 2>/dev/null | tee >(
# Audio playback branch
aplay -r 171k -f S16_LE -t raw -c 1 2>/dev/null || \
play -r 171k -t raw -e signed-integer -b 16 -c 1 - 2>/dev/null
) >(
# RDS decoding branch
redsea -r 171k -p | while IFS= read -r line; do
[ -z "$line" ] && continue
if ! echo "$line" | jq -e . >/dev/null 2>&1; then
continue
fi
prog_type=$(echo "$line" | jq -r '.prog_type // empty')
partial_radiotext=$(echo "$line" | jq -r '.partial_radiotext // empty')
partial_ps=$(echo "$line" | jq -r '.partial_ps // empty')
if [ -n "$prog_type" ]; then
last_prog_type="$prog_type"
fi
if [ -n "$partial_radiotext" ]; then
last_partial_radiotext="$partial_radiotext"
fi
if [ -n "$partial_ps" ]; then
last_partial_ps="$partial_ps"
fi
output="\033[1;1H\033[2K"
if [ -n "$last_prog_type" ]; then
output="${output}: $last_prog_type"
fi
output="${output}\033[2;1H\033[2K"
if [ -n "$last_partial_radiotext" ]; then
output="${output}: $last_partial_radiotext"
fi
output="${output}\033[3;1H\033[2K"
if [ -n "$last_partial_ps" ]; then
output="${output}: $last_partial_ps"
fi
echo -e "$output"
done
) >/dev/null
# Wait for background processes
wait


