Docs header transparent bg

bundle exec

bundle-exec - 在捆绑器上下文中执行命令

bundle exec [--keep-file-descriptors] command

描述

此命令执行命令,使 Gemfile(5) 中指定的 gem 在 Ruby 程序中可供 require 使用。

本质上,如果您通常会运行类似 rspec spec/my_spec.rb 的命令,并且您想使用 Gemfile(5) 中指定的 gem 并通过 bundle install(1) 安装,您应该运行 bundle exec rspec spec/my_spec.rb

请注意,bundle exec 不需要在 shell 的 $PATH 上提供可执行文件。

选项

--keep-file-descriptors
将所有文件描述符传递给新进程。从捆绑器版本 2.2.26 开始,默认值为 true。将其设置为 false 现在已弃用。

Bundle Install --binstubs

如果您在 bundle install(1) 中使用 --binstubs 标志,捆绑器将自动创建一个目录(默认情况下为 app_root/bin),其中包含捆绑包中 gem 提供的所有可执行文件。

使用 --binstubs 后,bin/rspec spec/my_spec.rb 等同于 bundle exec rspec spec/my_spec.rb

环境修改

bundle exec 对 shell 环境进行了一些更改,然后完全执行您指定的命令。

  • 确保仍然可以从 bundle exec 调用的命令内部(使用 $BUNDLE_BIN_PATH)调用 shell 到 bundle
  • 将包含捆绑包的可执行文件(如 railsrspecrackup)的目录放在 $PATH
  • 确保如果在子 shell 中调用捆绑器,它使用相同的 Gemfile(通过设置 BUNDLE_GEMFILE
  • -rbundler/setup 添加到 $RUBYOPT,这将确保在子 shell 中调用的 Ruby 程序可以看到捆绑包中的 gem

它还修改了 Rubygems

  • 禁止加载捆绑包中不存在的其他 gem
  • 修改 gem 方法,如果捆绑包中存在与要求匹配的 gem,则为无操作,如果不存在,则引发 Gem::LoadError
  • 定义 Gem.refresh 为无操作,因为在使用捆绑器时源索引始终被冻结,并且为了防止系统中的 gem 泄漏到环境中
  • 覆盖Gem.bin_path以使用捆绑包中的 gem,使系统可执行文件正常工作
  • 将捆绑包中的所有 gem 添加到 Gem.loaded_specs

最后,bundle exec 还会在锁定文件和 Gemfile 不匹配时隐式修改Gemfile.lock。Bundler 需要 Gemfile 来确定 gem 的组、autorequire 和平台等信息,这些信息不会存储在锁定文件中。为了使bundle exec 成功,Gemfile 和锁定文件必须同步,因此bundle exec 会事先更新锁定文件。

加载

默认情况下,当尝试使用带有 Ruby shebang 的文件执行bundle exec 时,Bundler 会Kernel.load 该文件,而不是使用Kernel.exec。在绝大多数情况下,这是一种性能提升。在极少数情况下,这可能会导致一些细微的副作用(例如依赖于$0__FILE__ 的确切内容),并且可以通过启用disable_exec_load 设置来禁用此优化。

外壳命令

任何打开子 shell 的 Ruby 代码(如system、反引号或%x{})都会自动使用当前的 Bundler 环境。如果需要对当前捆绑包中不包含的 Ruby 命令执行外壳命令,请使用with_unbundled_env 方法并带一个代码块。在代码块内创建的任何子 shell 都将获得 Bundler 激活之前的环境。例如,Homebrew 命令运行 Ruby,但不能在捆绑包内运行

Bundler.with_unbundled_env do
  `brew install wget`
end

如果要对不同的捆绑包执行外壳命令,也需要使用with_unbundled_env。在子 shell 中运行的任何 Bundler 命令都会继承当前的 Gemfile,因此需要在不同捆绑包的上下文中运行的命令也需要使用with_unbundled_env

Bundler.with_unbundled_env do
  Dir.chdir "/other/bundler/project" do
    `bundle exec ./script`
  end
end

Bundler 提供了包装systemexec 的便捷帮助程序,可以使用以下方式使用它们

Bundler.clean_system('brew install wget')
Bundler.clean_exec('brew install wget')

Rubygems 插件

目前,Rubygems 插件系统要求在任何 Ruby 代码需要rubygems.rb 时,在任何已安装 gem 的加载路径上包含名为rubygems_plugin.rb 的所有文件。这包括安装到系统中的可执行文件,如railsrackuprspec

由于 Rubygems 插件可以包含任意 Ruby 代码,它们通常会自行激活或激活其依赖项。

例如,gemcutter 0.5 gem 依赖于 json_pure。如果你安装了该版本的 gemcutter(即使你安装了没有此问题的更新版本),Rubygems 将激活 gemcutter 0.5json_pure <latest>

如果你的 Gemfile(5) 也包含 json_pure(或依赖于 json_pure 的 gem),系统上的最新版本可能与你 Gemfile(5) 中的版本冲突,或者与你 Gemfile.lock 中的快照版本冲突。

如果发生这种情况,bundler 会说

You have already activated json_pure 1.4.6 but your Gemfile
requires json_pure 1.4.3. Consider using bundle exec.

在这种情况下,你几乎肯定想要删除包含有问题的 gem 插件的底层 gem。通常,这些插件的作者(在本例中为 gemcutter gem)已经发布了更新版本,这些版本在插件方面更加谨慎。

你可以通过运行以下命令找到包含 gem 插件的所有 gem 的列表:

ruby -e "puts Gem.find_files('rubygems_plugin.rb')"

至少,你应该删除除每个 gem 插件的最新版本之外的所有版本,并删除所有未使用的 gem 插件(gem uninstall gem_name)。

在 GitHub 上编辑此文档,如果你发现错误或注意到缺少内容。