When writing bash scripts that interact with Ruby gems, you might expect gem list <name>
to return a non-zero exit code when the gem isn't found. However, this command always returns 0, making it unreliable for scripting purposes.
gem list nonexistent_gem
echo $? # Outputs 0 even when gem doesn't exist
Here are several reliable ways to check gem installation status in bash scripts:
Method 1: Using grep with quiet mode
if ! gem list -i <name> > /dev/null 2>&1; then
echo "Gem <name> is not installed"
# Installation logic here
fi
Method 2: The built-in -i flag
RubyGems actually provides a better way:
if gem list -i "^<name>$" > /dev/null; then
echo "Gem is installed"
else
echo "Gem is missing"
fi
Method 3: Using exact matching
For more precise matching (to avoid partial matches):
if gem list | grep -qw "^<name> "; then
echo "Found exact match"
fi
For checking multiple gems at once:
required_gems=("rails" "bundler" "rake")
missing_gems=()
for gem in "${required_gems[@]}"; do
if ! gem list -i "^${gem}$" > /dev/null; then
missing_gems+=("$gem")
fi
done
if [ ${#missing_gems[@]} -ne 0 ]; then
echo "Missing gems: ${missing_gems[*]}"
# Installation logic here
fi
When checking many gems, it's more efficient to run gem list
once:
installed_gems=$(gem list)
check_gem_installed() {
local gem_name=$1
if [[ "$installed_gems" =~ "${gem_name} " ]]; then
return 0
else
return 1
fi
}
To verify specific versions:
if gem list -i "^rails$" -v "6.1.4"; then
echo "Rails 6.1.4 is installed"
fi
When working with Ruby gems in bash scripts, many developers assume gem list
returns a non-zero exit code when a gem isn't found. However, this isn't the case - the command always returns 0, making simple conditional checks unreliable.
Here are three robust approaches to check gem installation from bash:
1. Using grep with Quiet Mode
The most straightforward method:
if ! gem list -i "^gem_name$" >/dev/null; then
echo "Gem not installed!"
# installation logic here
fi
2. Parsing JSON Output (More Reliable)
For more complex scenarios, use the JSON output format:
if [ "$(gem list -e "^rails$" --quiet)" == "false" ]; then
gem install rails
fi
3. Using gem query with Exact Match
A precise version check:
if ! gem query -n "^rails$" -i >/dev/null; then
echo "Installing missing gem..."
gem install rails -v '7.0.4'
fi
For checking several gems at once:
required_gems=("rails" "rspec" "pry")
for gem in "${required_gems[@]}"; do
if ! gem list -i "^${gem}$" >/dev/null; then
echo "Installing ${gem}..."
gem install "${gem}"
fi
done
To verify specific gem versions:
if ! gem list -i "^rails$" -v '7.0.4' >/dev/null; then
echo "Required Rails version 7.0.4 not found"
gem install rails -v '7.0.4'
fi
For scripts that check gems frequently, caching the gem list can improve performance:
gem_list_cache=$(gem list)
if ! grep -q "^rails " <<< "${gem_list_cache}"; then
gem install rails
fi