How to Check if a Ruby Gem is Installed from a Bash Script


3 views

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