Running a shell command from ruby

S

Steve Pauly

I am experimenting with running bash commands from within ruby. The
commands should be in an array, separated internally with semicolons.

The problem is that they do not get executed.

My script:

----
#!/usr/bin/ruby
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to
be added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end
----

The output from "puts k" looks good.
But why do the files f1 and f2 not get created?

I realize that executing commands this way in ruby may be bad practise,
but at least, why do the commands not execute?

Thanks in advance.
Steve.
 
J

Jean-Julien Fleck

script1=3D["touch ~/ruby/f1;touch ~/ruby/f2"] =A0 =A0#addl array elements=
to
But why do the files f1 and f2 not get created?

Does the directory ~/ruby/ already exist on your machine ?

Cheers,

--=20
JJ Fleck
PCSI1 Lyc=E9e Kl=E9ber
 
B

Brian Buckley

#!/usr/bin/ruby
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to
be added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end

Your block is not being called. I think the output you are seeing the is
from the first "puts", not the "puts" inside the block.

You need to call "each" on the Array returned by split, like this:

puts script1[0].split(/;/).each do |k|
puts k
system(k)
end

--Brian
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

I am experimenting with running bash commands from within ruby. The
commands should be in an array, separated internally with semicolons.

The problem is that they do not get executed.

My script:

----
#!/usr/bin/ruby
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to
be added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end
----

The output from "puts k" looks good.
But why do the files f1 and f2 not get created?

I realize that executing commands this way in ruby may be bad practise,
but at least, why do the commands not execute?

Thanks in advance.
Steve.

It has to do with block bindings. do ... end bind to the furthest left
method call on the line, so in this case, the block is being passed to the
puts method, not the split method.



def puts( *args , &block )
super "puts received: #{args.inspect}, and #{block ? 'a' : 'no'} block."
end

script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to be
added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

I am experimenting with running bash commands from within ruby. The
commands should be in an array, separated internally with semicolons.

The problem is that they do not get executed.

My script:

----
#!/usr/bin/ruby
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to
be added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end
----

The output from "puts k" looks good.
But why do the files f1 and f2 not get created?

I realize that executing commands this way in ruby may be bad practise,
but at least, why do the commands not execute?

Thanks in advance.
Steve.

It has to do with block bindings. do ... end bind to the furthest left
method call on the line, so in this case, the block is being passed to the
puts method, not the split method.



def puts( *args , &block )
super "puts received: #{args.inspect}, and #{block ? 'a' : 'no'} block."
end


script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to be
added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end

Here is a solution that creates the files.

----------

script1=["touch ~/f1;touch ~/f2"] #addl array elements to be added
script1[0].split(/;/).each do |k|
puts k
system k
end

----------

Note that {} has the kind of binding that you were looking for, but that
split does not take a block (which is why I added the each method).

though I don't understand your format, are you wanting them to be separated
by being elements in an array, or by splitting a string on semicolons? Right
now, any other elements in this array will be ignored, because you only look
at the one in index zero. (what is the point of the Array?)

But you also have an issue if you split on semicolons, that assumes all
semicolons are valid delimiters. Depending on context, this may not be the
case. For example, what if the String was:
%{echo "if ARGV.empty? ; puts 'no args' else puts 'got args' end" >
argchecker.rb ; ruby argchecker.rb 1 2 3 ; ruby argchecker.rb}

Then you want it to find these commands
[
"echo \"if ARGV.empty? ; puts 'no args' else puts 'got args' end\" >
argchecker.rb ",
" ruby argchecker.rb 1 2 3 ",
" ruby argchecker.rb"
]

But split(';') will give you these commands
[
"echo \"if ARGV.empty? ",
" puts 'no args' else puts 'got args' end\" > argchecker.rb ",
" ruby argchecker.rb 1 2 3 ",
" ruby argchecker.rb"
]


I think the best solution (easiest to implement, least likely to have bugs,
most straightforward) is to keep each command separated in the Array, and
not try to pull them from the string. If you do need to do that, you must
either be careful to avoid using a semicolon in a way that is not a command
delimiter, or you must find/write a parser so that you can determine where
commands begin and end. I suppose you could also pick a different delimiter
that is really unlikely to ever show up outside of the delimiter context.
Some obscure unicode character, maybe.
 
S

Steve Pauly

Jean-Julien Fleck said:
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] � �#addl array elements to
But why do the files f1 and f2 not get created?

Does the directory ~/ruby/ already exist on your machine ?

Cheers,

Yes. It is where the ruby script is stored so I know it exists.
Thanks.
 
S

Steve Pauly

Brian said:
#!/usr/bin/ruby
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to
be added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end

Your block is not being called. I think the output you are seeing the is
from the first "puts", not the "puts" inside the block.

You need to call "each" on the Array returned by split, like this:

puts script1[0].split(/;/).each do |k|
puts k
system(k)
end

--Brian

Brian, you were right.

Stupid of me not to think of the .each method.

Thank you!
Steve.

revised script:

script1=["touch /home/holocene/ruby/f1;touch /home/holocene/ruby/f2"]
script1.length.times do |cnt|
puts "script1 item #{cnt}"
script1[0].split(/;/).each do |k|
puts k
system(k)
end

end
 
S

Steve Pauly

Josh said:
#!/usr/bin/ruby
It has to do with block bindings. do ... end bind to the furthest left
script1=["touch ~/ruby/f1;touch ~/ruby/f2"] #addl array elements to be
added
puts script1[0].split(/;/) do |k|
puts k
system(k)
end

Here is a solution that creates the files.

----------

script1=["touch ~/f1;touch ~/f2"] #addl array elements to be added
script1[0].split(/;/).each do |k|
puts k
system k
end

----------

Note that {} has the kind of binding that you were looking for, but that
split does not take a block (which is why I added the each method).

though I don't understand your format, are you wanting them to be
separated
by being elements in an array, or by splitting a string on semicolons?

My idea, as a learning exercise only,was to prove to myself that I could
use an array of strings to contain "multiple" bash commands in "each"
array element. Of course, my use of a ";" to delimit is probably ill
advised, but was done merely for a proof of concept.

Now that with the addition of ".each", it works and mystery (for me)
solved.

I will have to study your code below more.

Thanks to all.
Steve.



Right
now, any other elements in this array will be ignored, because you only
look
at the one in index zero. (what is the point of the Array?)

But you also have an issue if you split on semicolons, that assumes all
semicolons are valid delimiters. Depending on context, this may not be
the
case. For example, what if the String was:
%{echo "if ARGV.empty? ; puts 'no args' else puts 'got args' end" >
argchecker.rb ; ruby argchecker.rb 1 2 3 ; ruby argchecker.rb}

Then you want it to find these commands
[
"echo \"if ARGV.empty? ; puts 'no args' else puts 'got args' end\" >
argchecker.rb ",
" ruby argchecker.rb 1 2 3 ",
" ruby argchecker.rb"
]

But split(';') will give you these commands
[
"echo \"if ARGV.empty? ",
" puts 'no args' else puts 'got args' end\" > argchecker.rb ",
" ruby argchecker.rb 1 2 3 ",
" ruby argchecker.rb"
]


I think the best solution (easiest to implement, least likely to have
bugs,
most straightforward) is to keep each command separated in the Array,
and
not try to pull them from the string. If you do need to do that, you
must
either be careful to avoid using a semicolon in a way that is not a
command
delimiter, or you must find/write a parser so that you can determine
where
commands begin and end. I suppose you could also pick a different
delimiter
that is really unlikely to ever show up outside of the delimiter
context.
Some obscure unicode character, maybe.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top