如何将命令行参数传递给rake任务

我有一个耙子任务,需要插入一个值到多个数据库。

我想通过命令行或其他 rake任务将此值传递给rake任务。

我该怎么做?

选项和依赖关系需要在数组内:

namespace :thing do desc "it does a thing" task :work, [:option, :foo, :bar] => [:environment] do |t, args| puts "work", args end task :another, [:option, :foo, :bar] => [:environment] do |t, args| puts "another #{args}" Rake::Task["thing:work"].invoke(args[:option], args[:foo], args[:bar]) # or splat the args # Rake::Task["thing:work"].invoke(*args) end end 

然后

 rake thing:work[1,2,3] => work: {:option=>"1", :foo=>"2", :bar=>"3"} rake thing:another[1,2,3] => another {:option=>"1", :foo=>"2", :bar=>"3"} => work: {:option=>"1", :foo=>"2", :bar=>"3"} 

注意:变量ttask简称。 这是任务对象,除非你知道你在做什么,否则不是很有帮助。

您可以通过向任务调用添加符号参数来指定rake中的形式参数。 例如:

 require 'rake' task :my_task, [:arg1, :arg2] do |t, args| puts "Args were: #{args}" end task :invoke_my_task do Rake.application.invoke_task("my_task[1, 2]") end # or if you prefer this syntax... task :invoke_my_task_2 do Rake::Task[:my_task].invoke(3, 4) end # a task with prerequisites passes its # arguments to it prerequisites task :with_prerequisite, [:arg1, :arg2] => :my_task #<- name of prerequisite task # to specify default values, # we take advantage of args being a Rake::TaskArguments object task :with_defaults, :arg1, :arg2 do |t, args| args.with_defaults(:arg1 => :default_1, :arg2 => :default_2) puts "Args with defaults were: #{args}" end 

然后,从命令行:

 > rake my_task [1,2]
参数是:{:arg1 =>“1”,:arg2 =>“2”}

 >耙“my_task [1,2]”
参数是:{:arg1 =>“1”,:arg2 =>“2”}

 > rake invoke_my_task
参数是:{:arg1 =>“1”,:arg2 =>“2”}

 > rake invoke_my_task_2
参数是:{:arg1 => 3,:arg2 => 4}

 > rake with_prerequisite [5,6]
参数是:{:arg1 =>“5”,:arg2 =>“6”}

 > rake with_defaults
具有默认值的参数是:{:arg1 =>:default_1,:arg2 =>:default_2}

 > rake with_defaults ['x','y']
具有默认值的参数是:{:arg1 =>“x”,:arg2 =>“y”}

如第二个例子所示,如果要使用空格,则目标名称周围的引号是必要的,以防止shell将空间中的参数拆分。

看看rake.rb中的代码,看来rake不会解析任务字符串来为先决条件提取参数,所以你不能执行task :t1 => "dep[1,2]" 。 为先决条件指定不同参数的唯一方法是在相关任务操作中显式调用它,如:invoke_my_task:invoke_my_task_2

请注意,某些shell(如zsh)要求您rake my_task\['arg1'\]括号: rake my_task\['arg1'\]

除了由kch回答(我没有找到如何发表评论,对不起):

rake命令之前,您不必将变量指定为ENV变量。 你可以像通常的命令行参数那样设置它们:

 rake mytask var=foo 

并从您的耙文件访问这些ENV变量像这样:

 p ENV['var'] # => "foo" 

如果你想传递命名参数(例如使用标准的OptionParser ),你可以使用这样的东西:

 $ rake user:create -- --user test@example.com --pass 123 

注意-- ,这是绕过标准Rake参数所必需的。 应该使用Rake 0.9.x<= 10.3.x。

较新的Rake已经改变了对--解析,现在你必须确保它没有传递给OptionParser#parse方法,例如parser.parse!(ARGV[2..-1])

 require 'rake' require 'optparse' # Rake task for creating an account namespace :user do |args| desc 'Creates user account with given credentials: rake user:create' # environment is required to have access to Rails models task :create do options = {} OptionParser.new(args) do |opts| opts.banner = "Usage: rake user:create [options]" opts.on("-u", "--user {username}","User's email address", String) do |user| options[:user] = user end opts.on("-p", "--pass {password}","User's password", String) do |pass| options[:pass] = pass end end.parse! puts "creating user account..." u = Hash.new u[:email] = options[:user] u[:password] = options[:pass] # with some DB layer like ActiveRecord: # user = User.new(u); user.save! puts "user: " + u.to_s puts "account created." exit 0 end end 

exit时会确保额外的参数不会被解释为Rake任务。

另外,参数的捷径应该起作用:

  rake user:create -- -u test@example.com -p 123 

当耙子脚本看起来像这样,也许是时候寻找另一个工具,可以让这个刚刚开箱。

我从这两个网站找到了答案: 网络 狂人和Aimred 。

你需要使用这种技术的版本> 0.8的耙

正常的rake任务描述是这样的:

 desc 'Task Description' task :task_name => [:depends_on_taskA, :depends_on_taskB] do #interesting things end 

要传递论据,请做三件事:

  1. 在任务名称后面添加参数名称,用逗号分隔。
  2. 把依赖关系放在最后使用:needs => […]
  3. 放置| t,args | 做完之后。 (t是这个任务的对象)

要访问脚本中的参数,请使用args.arg_name

 desc 'Takes arguments task' task :task_name, :display_value, :display_times, :needs => [:depends_on_taskA, :depends_on_taskB] do |t, args| args.display_times.to_i.times do puts args.display_value end end 

要从命令行调用此任务,请将它传递给[] s中的参数

 rake task_name['Hello',4] 

会输出

 Hello Hello Hello Hello 

如果你想从另一个任务调用这个任务,并传递它的参数,使用invoke

 task :caller do puts 'In Caller' Rake::Task[:task_name].invoke('hi',2) end 

那么命令

 rake caller 

会输出

 In Caller hi hi 

我没有找到一种方法来传递参数作为依赖的一部分,因为下面的代码中断:

 task :caller => :task_name['hi',2]' do puts 'In Caller' end 

另一个常用的选项是传递环境变量。 在你的代码中,你可以通过ENV['VAR']读取它们,并且可以在rake命令之前传递它们

 $ VAR=foo rake mytask 

其实@尼克Desjardins回答完美。 但只是教育:你可以使用肮脏的方法:使用ENV参数

 task :my_task do myvar = ENV['myvar'] puts "myvar: #{myvar}" end rake my_task myvar=10 #=> myvar: 10 

我不知道如何通过参数和环境,直到我解决了这个问题:

 namespace :db do desc 'Export product data' task :export, [:file_token, :file_path] => :environment do |t, args| args.with_defaults(:file_token => "products", :file_path => "./lib/data/") #do stuff [...] end end 

然后我这样打电话:

 rake db:export['foo, /tmp/'] 
 desc 'an updated version' task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args| puts args[:arg1] end 

我在rake文件中使用了一个常规的ruby参数:

 DB = ARGV[1] 

那么我把文件底部的rake任务(因为rake会根据这个参数的名字来查找一个任务)。

 task :database_name1 task :database_name2 

命令行:

 rake mytask db_name 

这比var = foo ENV var和任务参数[blah,blah2]解决方案感觉更清洁。
该存根是有点jenky,但不是太糟糕,如果你只是有一些一次性设置的环境

我只是想能够运行:

 $ rake some:task arg1 arg2 

很简单,对吧? (不!)

Rake将arg1arg2解释为任务,并尝试运行它们。 所以我们只是放弃它之前。

 namespace :some do task task: :environment do arg1, arg2 = ARGV # your task... exit end end 

拿那个,括号!

免责声明 :我希望能够在一个非常小的宠物项目中做到这一点。 由于您失去了链接rake任务(即rake task1 task2 task3 )的能力,因此不打算用于“真实世界”的使用。 国际海事组织不值得。 只需使用丑陋的rake task[arg1,arg2]

上面的答案中传递参数的方法是正确的。 然而为了用参数运行rake任务,在较新版本的rails中有一个小的技术性问题

它将与rake“namespace:taskname ['argument1']”

请注意从命令行运行任务中的反转引号。

要将参数传递给默认任务,可以这样做。 例如,说“版本”是你的论点:

 task :default, [:version] => [:build] task :build, :version do |t,args| version = args[:version] puts version ? "version is #{version}" : "no version passed" end 

那么你可以这样调用它:

 $ rake no version passed 

要么

 $ rake default[3.2.1] version is 3.2.1 

要么

 $ rake build[3.2.1] version is 3.2.1 

但是,我还没有找到一种方法来避免在传递参数时指定任务名称(默认或构建)。 如果有人知道一个方法,我很想听听。

我喜欢参数传递的“querystring”语法,特别是当有很多参数需要传递时。

例:

 rake "mytask[width=10&height=20]" 

“查询字符串”是:

 width=10&height=20 

警告:请注意,语法是rake "mytask[foo=bar]"不是 rake mytask["foo=bar"]

当使用Rack::Utils.parse_nested_query在rake任务中解析时,我们得到一个Hash

 => {"width"=>"10", "height"=>"20"} 

(很酷的是你可以传递哈希和数组,下面更多)

这是如何实现这一点:

 require 'rack/utils' task :mytask, :args_expr do |t,args| args.with_defaults(:args_expr => "width=10&height=10") options = Rack::Utils.parse_nested_query(args[:args_expr]) end 

以下是我在delayed_job_active_record_threaded gem中使用Rails的更多扩展示例:

 bundle exec rake "dj:start[ebooks[workers_number]=16&ebooks[worker_timeout]=60&albums[workers_number]=32&albums[worker_timeout]=120]" 

像上面那样解析,具有环境依赖性(为了加载Rails环境)

 namespace :dj do task :start, [ :args_expr ] => :environment do |t, args| # defaults here... options = Rack::Utils.parse_nested_query(args[:args_expr]) end end 

给出以下options

 => {"ebooks"=>{"workers_number"=>"16", "worker_timeout"=>"60"}, "albums"=>{"workers_number"=>"32", "worker_timeout"=>"120"}} 

上面介绍的大多数方法都不适合我,也许在新版本中不推荐使用。 最新的指南可以在这里找到: http : //guides.rubyonrails.org/command_line.html#custom-rake-tasks

指南中的复制和粘贴答案在这里:

 task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args| # You can use args from here end 

像这样调用它

 bin/rake "task_name[value 1]" # entire argument string should be quoted 

如果你不能记住什么论点的位置是什么,你想做一些像红宝石参数哈希。 您可以使用一个参数传入一个字符串,然后将该字符串正则表达为一个选项哈希。

 namespace :dummy_data do desc "Tests options hash like arguments" task :test, [:options] => :environment do |t, args| arg_options = args[:options] || '' # nil catch incase no options are provided two_d_array = arg_options.scan(/\W*(\w*): (\w*)\W*/) puts two_d_array.to_s + ' # options are regexed into a 2d array' string_key_hash = two_d_array.to_h puts string_key_hash.to_s + ' # options are in a hash with keys as strings' options = two_d_array.map {|p| [p[0].to_sym, p[1]]}.to_h puts options.to_s + ' # options are in a hash with symbols' default_options = {users: '50', friends: '25', colour: 'red', name: 'tom'} options = default_options.merge(options) puts options.to_s + ' # default option values are merged into options' end end 

并在命令行中获得。

 $ rake dummy_data:test["users: 100 friends: 50 colour: red"] [["users", "100"], ["friends", "50"], ["colour", "red"]] # options are regexed into a 2d array {"users"=>"100", "friends"=>"50", "colour"=>"red"} # options are in a hash with keys as strings {:users=>"100", :friends=>"50", :colour=>"red"} # options are in a hash with symbols {:users=>"100", :friends=>"50", :colour=>"red", :name=>"tom"} # default option values are merged into options 

在传递参数的时候,最好是选择一个输入文件,这可以是一个Excel或者任何你需要的东西,然后从那里读取你需要的数据结构和变量,包括需要的变量名称。 读取文件可以有以下结构。

  namespace :name_sapace_task do desc "Description task...." task :name_task => :environment do data = ActiveSupport::JSON.decode(File.read(Rails.root+"public/file.json")) if defined?(data) # and work whit yoour data, example is data["user_id"] end end 

示例json

 { "name_task": "I'm a task", "user_id": 389, "users_assigned": [389,672,524], "task_id": 3 } 

执行

 rake :name_task