The default Bash shell that ships with RHEL 10, Rocky Linux 10, and AlmaLinux 10 is functional, but it may not include the latest features and fixes available in Bash 5.2 and 5.3+. Building Bash from source gives you full control over the version running on your system and lets you take advantage of improvements like $EPOCHSECONDS, better associative arrays, nameref fixes, and loadable builtins.
This guide walks through the full process of compiling and installing the latest Bash release from GNU source on RHEL 10, Rocky Linux 10, and AlmaLinux 10. Every step includes verification so you know exactly what happened before moving on.
Step 1 – Check Your Current Bash Version
Before doing anything, confirm what version of Bash is currently installed on your system:
bash --version
Sample output:
GNU bash, version 5.2.26(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
You can also check the path of the active Bash binary:
which bash
# /usr/bin/bash
If you are running anything older than 5.3, this guide will get you up to date.
Step 2 – Why Upgrade to Bash 5.2 / 5.3+
There are solid practical reasons to build a newer Bash from source rather than relying on the distribution package:
- $EPOCHSECONDS and $EPOCHREALTIME – Built-in variables that return Unix timestamps without needing to call
date. Extremely useful in scripts that run in tight loops or need precise timing. - Associative array improvements – Better handling of associative arrays including fixes for unsetting elements and iterating over keys in edge cases.
- Nameref variable fixes – Bash 5.2+ resolved several long-standing bugs with
declare -nnameref variables, making indirect variable references more reliable. - Loadable builtins – Support for dynamically loading builtins like
sleep,mkdir,rmdir, and others directly into the shell, avoiding fork/exec overhead in performance-sensitive scripts. - Readline 8.2+ integration – Improved command-line editing, better Unicode support, and new bindable commands.
- Security patches – Each release includes fixes for parsing bugs and edge cases that can cause unexpected behavior in production scripts.
Step 3 – Install Build Dependencies
You need a C compiler and a handful of development libraries to build Bash from source. Install them with dnf:
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y gcc make bison flex ncurses-devel readline-devel texinfo
Verify that gcc and make are available:
gcc --version
make --version
Both commands should return version information without errors. If gcc is not found, double-check that the Development Tools group installed correctly.
Step 4 – Download the Latest Bash Source
Head over to the official GNU FTP mirror and grab the latest release. At the time of writing, Bash 5.3 is the newest stable version:
cd /tmp
BASH_VERSION="5.3"
wget https://ftp.gnu.org/gnu/bash/bash-${BASH_VERSION}.tar.gz
Verify the download completed and check the file size:
ls -lh /tmp/bash-${BASH_VERSION}.tar.gz
The tarball should be roughly 10-11 MB. If the file is suspiciously small or missing, re-run the wget command or check your network connection.
Extract the archive:
tar -xvzf /tmp/bash-${BASH_VERSION}.tar.gz -C /tmp/
Confirm the source directory exists:
ls -d /tmp/bash-${BASH_VERSION}
Step 5 – Configure, Compile, and Install Bash
Move into the source directory and run the configure script. We install to /usr/local so the new binary lands at /usr/local/bin/bash and does not overwrite the system default:
cd /tmp/bash-${BASH_VERSION}
./configure --prefix=/usr/local
Watch the output for any errors. A successful configure run ends with a line like:
configure: creating ./config.status
config.status: creating Makefile
Now compile the source. Use the -j flag with nproc to speed things up on multi-core systems:
make -j$(nproc)
Verify the build succeeded by checking the exit code and confirming the binary exists:
echo $?
# Should print 0
ls -l ./bash
Run the test suite if you want extra confidence (optional but recommended):
make test
Finally, install the compiled binary and supporting files:
sudo make install
Verify the new binary is in place:
/usr/local/bin/bash --version
You should see output reflecting the version you just compiled, for example:
GNU bash, version 5.3.0(1)-release (x86_64-pc-linux-gnu)
Step 6 – Add New Bash to /etc/shells
Before you can set the new Bash as a login shell, it must be listed in /etc/shells. Check if it is already there:
grep '/usr/local/bin/bash' /etc/shells
If there is no output, add it:
echo '/usr/local/bin/bash' | sudo tee -a /etc/shells
Verify the entry was added:
tail -3 /etc/shells
You should see /usr/local/bin/bash in the list.
Step 7 – Change the Default Shell for Your User
Use chsh to set the new Bash as your default login shell:
chsh -s /usr/local/bin/bash
You can also change the shell for another user (requires root):
sudo chsh -s /usr/local/bin/bash username
Verify the change took effect:
grep $USER /etc/passwd
The last field on the line should now show /usr/local/bin/bash.
Log out and log back in, then confirm:
echo $BASH_VERSION
Step 8 – Verify the Installation
Run a few quick checks to make sure everything is working correctly:
# Check version
bash --version
# Check which binary is in use
which bash
# Confirm the shell variable
echo $SHELL
# Quick feature test - EPOCHSECONDS
echo "Current Unix timestamp: $EPOCHSECONDS"
If which bash still returns /usr/bin/bash, you may need to update your PATH. Add this to your ~/.bashrc:
export PATH="/usr/local/bin:$PATH"
Then reload:
source ~/.bashrc
which bash
New Features Worth Knowing About
Here is a quick look at some of the features that make upgrading worthwhile.
$EPOCHSECONDS and $EPOCHREALTIME
These variables give you Unix timestamps directly in Bash without forking to date:
# Seconds since epoch
echo $EPOCHSECONDS
# Microsecond precision
echo $EPOCHREALTIME
# Practical use - timing a command
start=$EPOCHREALTIME
sleep 2
end=$EPOCHREALTIME
echo "Elapsed: $(echo "$end - $start" | bc) seconds"
Associative Array Improvements
Bash 5.2+ handles associative arrays more reliably, especially around unsetting and iterating:
declare -A servers
servers[web1]="192.168.1.10"
servers[web2]="192.168.1.11"
servers[db1]="192.168.1.20"
# Iterate over keys
for host in "${!servers[@]}"; do
echo "$host -> ${servers[$host]}"
done
# Get the number of elements
echo "Total servers: ${#servers[@]}"
Nameref Variables
Nameref variables (declare -n) let you create references to other variables. Bash 5.2 and 5.3 fixed several edge cases that caused unexpected behavior in earlier versions:
setup_config() {
local -n ref=$1
ref="configured"
}
status="pending"
setup_config status
echo $status
# Output: configured
Loadable Builtins
Bash supports loading extra builtins at runtime to avoid the overhead of external commands. After building from source, the loadable builtins are available under /usr/local/lib/bash:
# List available loadable builtins
ls /usr/local/lib/bash/
# Enable the sleep builtin (avoids forking /usr/bin/sleep)
enable -f /usr/local/lib/bash/sleep sleep
# Now sleep runs as a builtin
type sleep
# sleep is a shell builtin
This is particularly useful in scripts that call sleep or mkdir thousands of times in a loop.
Troubleshooting
Configure fails with “no acceptable C compiler found”
This means gcc is not installed or not in your PATH. Reinstall the development tools:
sudo dnf groupinstall -y "Development Tools"
gcc --version
chsh: “/usr/local/bin/bash” is not listed in /etc/shells
You skipped Step 6. Add the shell path first:
echo '/usr/local/bin/bash' | sudo tee -a /etc/shells
chsh -s /usr/local/bin/bash
Old version still shows after installation
Bash caches the path to executables. Clear the hash table and check again:
hash -r
which bash
bash --version
If /usr/bin/bash still takes priority, make sure /usr/local/bin comes first in your PATH variable as shown in Step 8.
make fails with readline errors
If the build fails with errors related to readline, make sure the development headers are installed:
sudo dnf install -y readline-devel ncurses-devel
Then clean and rebuild:
make clean
./configure --prefix=/usr/local
make -j$(nproc)
sudo make install
Scripts break because /bin/bash is still old
Scripts with #!/bin/bash as the shebang will still use the system Bash. If you need a specific script to use the new version, change its shebang to:
#!/usr/local/bin/bash
Or use the more portable approach:
#!/usr/bin/env bash
This will pick up whichever bash comes first in your PATH.
Reverting to the system default Bash
If you need to switch back to the original system Bash for any reason:
chsh -s /usr/bin/bash
Cleanup
Once you have confirmed everything works, remove the source files to free up space:
rm -rf /tmp/bash-5.3 /tmp/bash-5.3.tar.gz
Summary
You now have the latest Bash running on your RHEL 10, Rocky Linux 10, or AlmaLinux 10 system. Building from source is straightforward and gives you access to features and fixes that distribution packages may lag behind on. The key steps were: installing build dependencies, downloading and compiling the source, registering the new shell in /etc/shells, and setting it as your default.
Keep an eye on the GNU Bash releases page for future updates. When a new version drops, you can repeat this process to stay current.























































