How to pass command line arguments to a rake task
我有一个rake任务,需要在多个数据库中插入一个值。
我想把这个值从命令行传递到rake任务,或者从另一个rake任务传递。
我该怎么做?
通过向任务调用添加符号参数,可以在rake中指定正式参数。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
然后,从命令行:
1 2 3 | > rake my_task[1,2] Args were: {:arg1=>"1", :arg2=>"2 <div class="suo-content">[collapse title=""]<ul><li>这并不能告诉我如何用另一个任务的参数运行rake任务。它只涉及命令行的使用</li><li>要在命名空间内调用任务,请执行以下操作:rake::task['namespace:task']。</li><li>实际上我很惊讶,我已经找了很多次这个问题的答案,它一直是rake任务arg1=2 arg2=3。当参数是串联的时,这就简单多了。</li><li>谢谢,我特别需要将参数传递给先决条件任务,您的示例工作得很好。</li><li>@罗伯,@nick:"特别需要把论点传递给先决条件任务。"我看不到一个向prereq任务显式传递参数的示例。我错过什么了吗?有没有办法做到这一点,而不是调用?</li><li>是否可以连续多次调用任务?我试过<wyn>5.times { Rake::Task[:my_task].invoke }</wyn>,但它只第一次起作用。</li><li>这是一个单独的问题,igoru,但是调用只运行一次的原因是rake是面向依赖的,所以它只在需要时执行任务。对于一般任务,这意味着如果它还没有运行。若要显式执行任务,而不考虑其依赖项,或者如果需要,请调用Execute而不是Invoke。</li><li>注意:根据rake的说法,不赞成在任务中接受变量的语法:<wyn>WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.</wyn>。</li><li>请注意,zsh无法正确解析命令行参数(<wyn>zsh: no matches found: ...</wyn>),因此需要转义括号:<wyn>rake my_task\['arg1'\]</wyn>。来自robots.thoughtbot.com/post/18129303042/&hellip;</li><li>是的。如果你的评论没有被隐藏在"查看更多评论"链接后面,我就不会浪费10分钟来完成这项工作。</li><li>在你的<wyn>.zshrc</wyn>中加上<wyn>alias rake='noglob rake'</wyn>,然后忘记从括号中逃出。</li><li>当前轨道(5)的有效语法是:<wyn>task :task_name, [:var1, :var2] => :environment do |t, vars|</wyn>。内部任务变量看起来像:<wyn>{:var1 => val, :var2 => val}</wyn></li><li>为了完整性:任务不能显式地为其依赖任务的参数指定(或重写)值。</li><li>注意:不要在参数之间添加空格。用<wyn>rake my_task[1,2]</wyn>代替<wyn>rake my_task[1, 2]</wyn>。否则你会犯下可怕的错误,你会比你想承认的时间更长。</li></ul>[/collapse]</div><hr><P>除了由KCH回复(我没有找到如何对此发表评论,抱歉):</P><P>在<wyn>rake</wyn>命令之前,不必将变量指定为<wyn>ENV</wyn>变量。您可以像通常那样设置命令行参数:</P>[cc lang="ruby"]rake mytask var=foo |
从rake文件中访问这些变量作为env变量,比如:
1 | p ENV['var'] # =>"foo" |
选项和依赖项需要位于数组内部:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace :thing do desc"it does a thing" task :work, [:option, :foo, :bar] do |task, args| puts"work", args end task :another, [:option, :foo, :bar] do |task, 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 |
然后
1 2 3 | rake thing:work[1,2,3] => work: {:option=>"1", :foo=>"2", :bar=>"3 <div class="suo-content">[collapse title=""]<ul><li>另外,确保参数之间不使用空格。例如,不要这样做:<wyn>rake thing:work[1, 2, 3]</wyn>因为它不起作用,你会得到一个错误<wyn>Don't know how to build task</wyn>。</li><li>另外,请确保将参数括在字符串中。例如,从命令行运行rake任务,如<wyn>rake thing:work'[1,2,3]'</wyn></li><li>@DamianSimonPeter不需要使用字符串。可以简单地执行EDOCX1[24]值将是字符串!</li><li>不幸的是,zsh无法正确解析调用,您需要在zsh上键入如下命令:<wyn>rake thing:work\[1,2,3\]</wyn>,或者这个<wyn>rake 'thing:work[1,2,3]'</wyn>。</li><li>这对我来说是失败的,错误是:<wyn>Don't know how to build task 'environment' (see --tasks)</wyn>nick desjardins的回答非常有效。</li><li>@樱城建你可以从你的任务中删除<wyn>:environment</wyn>符号。Rails应用程序有一个:环境任务…</li><li>为什么不直接用<wyn>task</wyn>作为参数名,而不用说明<wyn>t</wyn>表示<wyn>task</wyn>?</li><li>@Blairanderson直言不讳。我喜欢它!-)</li><li>rake任务的名称、依赖项和参数的布局几乎是胡说八道。这个结论——虽然有效——并不是你凭直觉就能得出的。</li></ul>[/collapse]</div><hr><P>如果要传递命名参数(例如,使用标准<wyn>OptionParser</wyn>时),可以使用如下方法:</P>[cc lang="ruby"]$ rake user:create -- --user [email protected] --pass 123 |
注意
较新的rake已经改变了对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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 |
最后的
参数的快捷方式也应该有效:
1 | rake user:create -- -u test@example.com -p 123 |
当rake脚本看起来像这样的时候,也许是时候寻找另一个工具来允许它开箱即用了。
I've found the answer from these two websites: Net Maniac and Aimred.
You need to have version > 0.8 of rake to use this technique
The normal rake task description is this:
1 2 3 4 | desc 'Task Description' task :task_name => [:depends_on_taskA, :depends_on_taskB] do #interesting things end |
要传递参数,请执行以下三项操作:
要访问脚本中的参数,请使用args.arg_name
1 2 3 4 5 6 | 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 |
若要从命令行调用此任务,请将参数传递给它。
1 | rake task_name['Hello',4] |
意志输出
1 2 3 4 | Hello Hello Hello Hello |
如果要从另一个任务调用此任务并传递参数,请使用invoke
1 2 3 4 | task :caller do puts 'In Caller' Rake::Task[:task_name].invoke('hi',2) end |
然后命令
1 | rake caller |
意志输出
1 2 3 | In Caller hi hi |
我还没有找到将参数作为依赖项的一部分传递的方法,因为以下代码已中断:
1 2 3 | task :caller => :task_name['hi',2]' do puts 'In Caller' end |
另一个常用的选项是传递环境变量。在您的代码中,您通过
1 | $ VAR=foo rake mytask |
实际上,@nick desjardins的回答很完美。但仅仅是为了教育:你可以使用肮脏的方法:使用
1 2 3 4 5 6 7 | task :my_task do myvar = ENV['myvar'] puts"myvar: #{myvar}" end rake my_task myvar=10 #=> myvar: 10 |
我不知道如何传递args和:环境,直到我解决了这个问题:
1 2 3 4 5 6 7 8 9 | 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 |
然后我这样叫:
1 | rake db:export['foo, /tmp/'] |
1 2 3 4 | desc 'an updated version' task :task_name, [:arg1, :arg2] => [:dependency1, :dependency2] do |t, args| puts args[:arg1] end |
I just wanted to be able to run:
1 | $ rake some:task arg1 arg2 |
简单,对吧?(不!)
rake将
1 2 3 4 5 6 7 8 9 | namespace :some do task task: :environment do arg1, arg2 = ARGV # your task... exit end end |
拿着,支架!
免责声明:我想在一个非常小的宠物项目中做到这一点。不适用于"真实世界",因为您失去了链rake任务的能力(即
我在rake文件中使用了常规的ruby参数:
1 | DB = ARGV[1] |
然后我在文件的底部截取rake任务(因为rake将根据这个参数名查找任务)。
1 2 | task :database_name1 task :database_name2 |
命令行:
1 | rake mytask db_name |
我觉得这比var=foo env var和task args[blah,blah2]解决方案更干净。存根有点简陋,但如果您只有几个一次性设置的环境,那么也不算太糟糕。
在上述答案中,传递参数的方法是正确的。然而,要用参数运行rake任务,在较新版本的rails中涉及到一个小的技术问题。
它将与rake"namespace:taskname['argument1']
注意从命令行运行任务时的引号。
我喜欢参数传递的"querystring"语法,特别是当有很多参数要传递时。
例子:
1 | rake"mytask[width=10&height=20]" |
"querystring"是:
1 | width=10&height=20 |
警告:注意语法是
当使用
1 2 3 4 5 6 7 | => {"width"=>"10","height"=>"20 <div class="suo-content">[collapse title=""]<ul><li>投反对票的人,想详细说明吗?</li></ul>[/collapse]</div><hr><P>要将参数传递给默认任务,可以这样做。例如,假设"版本"是您的论点:</P>[cc lang="ruby"]task :default, [:version] => [:build] task :build, :version do |t,args| version = args[:version] puts version ?"version is #{version}" :"no version passed" end |
然后你可以这样称呼它:
1 2 | $ rake no version passed |
或
1 2 | $ rake default[3.2.1] version is 3.2.1 |
或
1 2 | $ rake build[3.2.1] version is 3.2.1 |
但是,在传递参数时,我找不到避免指定任务名称(默认或生成)的方法。如果有人知道一种方法,我会很高兴听到的。
上面描述的大多数方法对我来说都不起作用,也许它们在新版本中被否决了。最新的指南可以在这里找到:http://guides.rubyonrails.org/command_line.html自定义rake任务
从指南中复制并粘贴ANS如下:
1 2 3 | task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args| # You can use args from here end |
像这样调用它
1 | bin/rake"task_name[value 1]" # entire argument string should be quoted |
如果你不想记住什么是参数位置,你想做一些像Ruby参数散列这样的事情。可以使用一个参数传入一个字符串,然后将该字符串正则化为选项哈希。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
在命令行中,你会得到。
1 2 3 4 5 6 7 8 9 | $ 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 <div class="suo-content">[collapse title=""]<ul><li>您的代码需要一些位置良好的空行。我不知道你是怎么看那面文字墙的。</li></ul>[/collapse]</div><p><center>[wp_ad_camp_4]</center></p><hr> <p> To run rake tasks with traditional arguments style: </p> [cc lang="ruby"]rake task arg1 arg2 |
然后使用:
1 2 3 | task :task do |_, args| puts"This is argument 1: #{args.first}" end |
添加以下rake gem补丁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Rake::Application.class_eval do alias origin_top_level top_level def top_level @top_level_tasks = [top_level_tasks.join(' ')] origin_top_level end def parse_task_string(string) # :nodoc: parts = string.split ' ' return parts.shift, parts end end Rake::Task.class_eval do def invoke(*args) invoke_with_call_chain(args, Rake::InvocationChain::EMPTY) end end |
While passing parameters, it is better option is an input file, can this be a excel a json or whatever you need and from there read the data structure and variables you need from that including the variable name as is the need.
To read a file can have the following structure.
1 2 3 4 5 6 7 8 | 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
1 2 3 4 5 6 | { "name_task":"I'm a task", "user_id": 389, "users_assigned": [389,672,524], "task_id": 3 } |
执行
1 | rake :name_task |