How to pass command line arguments to a rake task
Solution 1
Options and dependencies need to be inside arrays:
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
Then
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"}
NOTE: variable
task
is the task object, not very helpful unless you know/care about Rake internals.
RAILS NOTE:
If running the task from Rails, it's best to preload the environment by adding
=> [:environment]
which is a way to setup dependent tasks.
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
Solution 2
You can specify formal arguments in rake by adding symbol arguments to the task call. For example:
require 'rake'
task :my_task, [:arg1, :arg2] do |t, args|
puts "Args were: #{args} of class #{args.class}"
puts "arg1 was: '#{args[:arg1]}' of class #{args[:arg1].class}"
puts "arg2 was: '#{args[:arg2]}' of class #{args[:arg2].class}"
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
Then, from the command line:
> rake my_task[1,false] Args were: {:arg1=>"1", :arg2=>"false"} of class Rake::TaskArguments arg1 was: '1' of class String arg2 was: 'false' of class String > rake "my_task[1, 2]" Args were: {:arg1=>"1", :arg2=>"2"} > rake invoke_my_task Args were: {:arg1=>"1", :arg2=>"2"} > rake invoke_my_task_2 Args were: {:arg1=>3, :arg2=>4} > rake with_prerequisite[5,6] Args were: {:arg1=>"5", :arg2=>"6"} > rake with_defaults Args with defaults were: {:arg1=>:default_1, :arg2=>:default_2} > rake with_defaults['x','y'] Args with defaults were: {:arg1=>"x", :arg2=>"y"}
As demonstrated in the second example, if you want to use spaces, the quotes around the target name are necessary to keep the shell from splitting up the arguments at the space.
Looking at the code in rake.rb, it appears that rake does not parse task strings to extract arguments for prerequisites, so you can't do task :t1 => "dep[1,2]"
. The only way to specify different arguments for a prerequisite would be to invoke it explicitly within the dependent task action, as in :invoke_my_task
and :invoke_my_task_2
.
Note that some shells (like zsh) require you to escape the brackets: rake my_task\['arg1'\]
Solution 3
In addition to answer by kch (I didn't find how to leave a comment to that, sorry):
You don't have to specify variables as ENV
variables before the rake
command. You can just set them as usual command line parameters like that:
rake mytask var=foo
and access those from your rake file as ENV variables like such:
p ENV['var'] # => "foo"
Solution 4
If you want to pass named arguments (e.g. with standard OptionParser
) you could use something like this:
$ rake user:create -- --user [email protected] --pass 123
note the --
, that's necessary for bypassing standard Rake arguments. Should work with Rake 0.9.x, <= 10.3.x.
Newer Rake has changed its parsing of --
, and now you have to make sure it's not passed to the OptionParser#parse
method, for example with 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
at the end will make sure that the extra arguments won't be interpreted as Rake task.
Also the shortcut for arguments should work:
rake user:create -- -u [email protected] -p 123
When rake scripts look like this, maybe it's time to look for another tool that would allow this just out of box.
Solution 5
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:
desc 'Task Description'
task :task_name => [:depends_on_taskA, :depends_on_taskB] do
#interesting things
end
To pass arguments, do three things:
- Add the argument names after the task name, separated by commas.
- Put the dependencies at the end using :needs => [...]
- Place |t, args| after the do. (t is the object for this task)
To access the arguments in the script, use 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
To call this task from the command line, pass it the arguments in []s
rake task_name['Hello',4]
will output
Hello
Hello
Hello
Hello
and if you want to call this task from another task, and pass it arguments, use invoke
task :caller do
puts 'In Caller'
Rake::Task[:task_name].invoke('hi',2)
end
then the command
rake caller
will output
In Caller
hi
hi
I haven't found a way to pass arguments as part of a dependency, as the following code breaks:
task :caller => :task_name['hi',2]' do
puts 'In Caller'
end
Comments
-
Tilendor almost 2 years
I have a rake task that needs to insert a value into multiple databases.
I'd like to pass this value into the rake task from the command line, or from another rake task.
How can I do this?
-
Brian Maltzan about 13 years
-
Jonathan Allard over 9 yearsDocs have been mirrored by SeattleRb.
-
-
Tilendor about 15 yearsThis doesn't tell me how to run the rake task with arguments from another task. It covers only command line usage
-
gaqzi almost 15 yearsTo invoke a task within a namespace simpy do: Rake::Task['namespace:task'].invoke
-
JasonSmith almost 14 yearsFrankly I was hoping for rake task -- these --go --to -a program and my task could get them from ARGV. Unfortunately I'm not sure if that's possible however I am currently using your solution: rake var1=val1 var2=val2
-
opsb over 13 yearsActually amazed, I've looked for the answer to this so many times and it's always been rake task arg1=2 arg2=3. This is much simpler when the arguments are in series.
-
Rob over 13 yearsThanks, I particularly needed to pass arguments to prerequisite task, your examples work perfectly.
-
mu is too short over 13 years@jhs:
rake blah -- --these --go --to --a-program
(note the--
to tell rake that its switches have ended), see stackoverflow.com/questions/5086224/… -
inger over 13 years@Rob, @Nick: "particularly needed to pass arguments to prerequisite task". I can't see an example explicitly passing parameters to prereq task.. Did I miss something? Is there a way to do this, rather than invoking?
-
igorsantos07 almost 13 yearsIs there a way to call a task more than one time in a row? I tried
5.times { Rake::Task[:my_task].invoke }
and it only worked for the first time. -
Nick Desjardins almost 13 yearsThat's a separate question, Igoru, but the reason your call to invoke only runs once is that rake is dependency-oriented, so it will only execute a task if it is needed. For generic tasks that means if it hasn't already run. To explicitly execute a task regardless of its dependencies or if it is needed, call execute instead of invoke.
-
madh over 12 yearsThe format for this functionality has changed as this warning states:
'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
-
Ajedi32 almost 12 yearsNote: According to rake, this syntax for accepting variables in tasks is deprecated:
WARNING: 'task :t, arg, :needs => [deps]' is deprecated. Please use 'task :t, [args] => [deps]' instead.
-
Juanda over 11 yearsTo prevent frozen strings issues, use
dup
at the end: db = ARGV[1].dup -
Seth Bro almost 11 yearsNote that zsh fails to parse the command line arguments correctly (
zsh: no matches found: ...
), so you need to escape the brackets:rake my_task\['arg1'\]
. From robots.thoughtbot.com/post/18129303042/… -
Joe over 10 yearsFrom my perspective this really is the best answer. Bypass environment variable kludges, strange syntax with task arguments, the additional benefit for standard
--option-names
. My only suggestion would be to useexit
rather thanabort
asabort
will leave you with a return code of 1 to the shell. If the rake task is a part of a higher-level script it's more common to assume a non-zero exit is some type of error. -
GMA over 10 years@SethBro YES. If only your comment hadn't been hidden behind the "See more comments" link I wouldn't have wasted 10 minutes unable to make this work.
-
Rik Smith-Unna over 10 yearsI agree with Joe, this is the best answer. The natural thing is to use the same interface for passing options to rake as you would when passing options to a script.
-
Augustin Riedinger over 10 yearsI agree this is the best answer. Ain't there a way to bypass the ugly
--
? Like passingrake
arguments to the actual task or something? Liketask :my_task, :*args do |t, args|
or something? -
Augustin Riedinger over 10 yearsBesides, I don't understand what the
{username}
is here for. Where is it used? Why isn't it there in-u {username}
? Cheers -
Tombart over 10 yearsAs far as I know there's no way how to bypass ugly
--
(just not using rake).{username}
should be replaced by your real username. It's just a notation for variable, it's not interpreted by ruby. -
Dex about 10 yearsTo call this, go:
rake task_name[hello, world]
-
Gayle about 10 yearsfrom rake.rubyforge.org/files/doc/rakefile_rdoc.html "Just a few words of caution. The rake task name and its arguments need to be a single command line argument to rake. This generally means no spaces. If spaces are needed, then the entire rake + argument string should be quoted. Something like this: rake "name[billy bob, smith]" "
-
Justin Tanner over 9 years
exit("account created.")
is causing an errorrake aborted!
wouldn'tputs "account created"; exit(0)
be a better approach? -
pawel7318 over 9 yearsIt worked for me after I
ARGV.shift
twice to removecreate:user
and--
fromARGV
. I'm sure it's not the way it should be done. I will appreciate if someone will show how to fix it properly. -
Tombart over 9 years@pawel7318 Which version of Rake do you use? Rake doesn't seem to follow semantic versioning conventions, there is a compatibility breaking change since
10.4.0
-
Tombart over 9 yearsThe way how Rake parses ARGV was changed in
10.4.1
and reverted in10.4.2
. github.com/ruby/rake/commit/… -
pawel7318 over 9 yearsI'm using 10.4.2. I created new question here.
-
ZiggyTheHamster almost 9 yearsIf you need a JSON instructions file for your Rake task, you're probably doing too many things in your Rake task.
-
jeffdill2 over 8 yearsThis is way over-complicating something that's incredibly simple.
-
Chandrashekhar Singh over 8 yearsAdd
alias rake='noglob rake'
in your.zshrc
and forget escaping the brackets. -
Andre Figueiredo about 8 yearsEvent better
db = ARGV[1].dup unless ARGV[1].nil?
to prevent exception of duping a nil. -
res almost 8 yearsvalid syntax for current rails (5) is:
task :task_name, [:var1, :var2] => :environment do |t, vars|
. Inside task vars looks like:{:var1 => val, :var2 => val}
-
fatty almost 8 yearsNeeded to make this
_, arg1, arg2 = ARGV
as the first arg was seen to be the name of the rake task. But thatexit
is a neat trick. -
rpbaltazar almost 8 yearsAlso, make sure you don't use spaces between the arguments. E.g don't do this:
rake thing:work[1, 2, 3]
as it won't work and you'll get an errorDon't know how to build task
-
Nuclearman over 7 years
rake task[arg1,arg2] && rake task2 && rake task3
Not sure if that's less ugly thanrake task[arg1,arg2] task2 task3
. Probably less efficient though. -
theterminalguy over 7 yearsAlso, make sure you enclose the argument in string. e.g from your command line run the rake task like so
rake thing:work'[1,2,3]'
-
Blair Anderson over 7 years@DamianSimonPeter you do not need to use strings. can simply do
rake thing:workd[true,false,cheese]
the values will be strings! -
valheru over 7 yearsWhat about when you're using bundle exec rake?
-
William Entriken over 7 yearsFor completeness: a task cannot explicitly specify (or override) values for its dependent task's arguments.
-
hutusi almost 7 yearsUnfortuanely, zsh can not parse the call correctly, you need type the command on zsh like this:
rake thing:work\[1,2,3\]
, or thisrake 'thing:work[1,2,3]'
-
sakurashinken about 6 yearsThis failed for me with the error
Don't know how to build task 'environment' (see --tasks)
Nick Desjardins answer worked great. -
Blair Anderson about 6 years@sakurashinken you can remove the
:environment
symbol from your task. rails applications have an :environment task... -
Joshua Pinter about 6 yearsYour code needs a few well-placed empty lines. I don't know how you read that wall of text.
-
Joshua Pinter about 6 yearsInstead of having a note to explain that
t
meanstask
, why not just usetask
as the param name? -
Joshua Pinter about 6 yearsNOTE: Do not add a space between arguments. Use
rake my_task[1,2]
instead ofrake my_task[1, 2]
. Otherwise you get the dreadedDon't know how to build task 'my_task[1,'
error and you'll be scratching your head for longer than you'd like to admit. -
Joshua Pinter about 6 years@BlairAnderson Explicitness. I love it! :-)
-
XtraSimplicity over 5 years
_, *args = ARGV
is perfect for capturing all subsequent arguments! Thanks heaps! -
user2490003 about 5 yearsRake tasks seem to have an almost nonsensical layout for name, dependencies, and arguments. The conclusion - while it works - is not something you could have arrived at intuitively.
-
stevec about 5 yearsThis is the best simplest answer IMO. It worked right away. What exactly does the
p
mean? -
kqcef about 5 years@user5783745 Like puts but instead of logging value.to_s to standard out it calls Obj.inspect and logs that to standard out. ruby-doc.org/core-2.0.0/Kernel.html#method-i-p
-
user2490003 almost 5 yearsThis is such a counter intuitive setup for a task runner / system. It's neither easily readable or easily writeable
-
Damien Roche over 4 yearsAnd override environment variables? Fantastic!
-
lzap over 4 yearsRake is utterly overengineered mess and this is the only way which worked. And it's not just me, this answer has the same amount of votes as the "correct" answer.
-
Olivier JM about 4 yearsThanks for this, great solution while maintaining the :environment
-
tundervirld over 3 yearsWe were using a rake task to do many complex things like a task. One of them was to be the input to an ETL process, and you could need many input fields to do it.We were using a rake task to do many complex things like a task. One of them was to be the input to an ETL process, and you could need many input fields to do it. If you are thinking that a Rake Task is for easiest thing only, maybe you aren't using in other complex context. Thanks for commenting.
-
vlsd about 3 yearsfor your last example with defaults, is that a recursive call to
with_defaults
or does the task name and the method name just happen to the be same? -
x-yuri about 3 yearsWhat's the point of escaping
x
andy
inrake with_defaults['x','y']
? Whatrake
gets iswith_defaults[x,y]
anyway. -
karatedog almost 3 years@muistooshort unfortunately (not knowing how it worked back in '11) this will try to run all the arguments passed as if they were tasks. One of the half ugly solution is to create empty tasks based on ARGV,content so these task will indeed be run, they just won't do anything, the second is to
exit
at the end of the task. Exiting is the easier, but that will break any compound task that try to run the exiting task along others asexit
will halt task execution and exit Rake. -
mu is too short almost 3 years@karatedog Are you sure about that? I just tried it to make sure and it seems okay, am I missing something?
-
karatedog almost 3 years@muistooshort Right, passing arguments with double dash works. I cannot correct the previous comment, the error was on passing linux style command line arguments like:
--switch1 value1 --switch2 value2
. -
karatedog almost 3 yearsthe side effect of using
exit 0
is this task exits Rake when it is finished. So if you have a task that calls 2 tasks, and it calls the above first, the second task won't run. -
Duarte over 2 yearsI get an error when trying this:
rake aborted! Don't know how to build task 'hello world'
-
guero64 about 2 yearsActually, I think single quote goes after
rake
; i.e.rake 'namespace1:task1["1","2","3"]'
. Otherwise thank you for helpful answer.