Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > `echo %!(*`

Reply
Thread Tools

`echo %!(*`

 
 
Tom Felker
Guest
Posts: n/a
 
      08-31-2003
Hello all,

Does anyone know a way to do backtick interpolation while protecting the
command's arguments from the shell, or bypassing the shell entirely? I'm
writing a script to rename badly named music files, and I have to pass the
bad name to vorbiscomment and read it's output.

Apparently Kernel::` is a method, but I can't figure out how to call it
with my own arguments. Is there a non-punctuation name for it? This
would only be useful if it could accept an argument list as an array and
not use the shell, as Kernel::system does.

Thanks,
--
Tom Felker, <(E-Mail Removed)>
<http://vlevel.sourceforge.net> - Stop fiddling with the volume knob.

I'm not comfortable with an idea that's not constantly being challenged.

 
Reply With Quote
 
 
 
 
Daniel Carrera
Guest
Posts: n/a
 
      08-31-2003
I'm not sure I understand what you're asking about backtick
interpolation. Can you give me a simple example of what you'd like the
backtick to do so I understand beter?

As for renaming a file, would File.rename do what you want? :

dcarrera ~ $ ls *.mp3
BadlyNamedFile.mp3
dcarrera ~ $ ruby -e 'File.rename("BadlyNamedFile.mp3", "NewName.mp3")'
dcarrera ~ $ ls *.mp3
NewName.mp3


On Mon, Sep 01, 2003 at 07:46:24AM +0900, Tom Felker wrote:
> Hello all,
>
> Does anyone know a way to do backtick interpolation while protecting the
> command's arguments from the shell, or bypassing the shell entirely? I'm
> writing a script to rename badly named music files, and I have to pass the
> bad name to vorbiscomment and read it's output.
>
> Apparently Kernel::` is a method, but I can't figure out how to call it
> with my own arguments. Is there a non-punctuation name for it? This
> would only be useful if it could accept an argument list as an array and
> not use the shell, as Kernel::system does.
>
> Thanks,
> --
> Tom Felker, <(E-Mail Removed)>
> <http://vlevel.sourceforge.net> - Stop fiddling with the volume knob.
>
> I'm not comfortable with an idea that's not constantly being challenged.
>


--
Daniel Carrera, Math PhD student at UMD. PGP KeyID: 9AF77A88
.-"~~~"-.
/ O O \ ATTENTION ALL PASCAL USERS:
: s :
\ \___/ / To commemorate the anniversary of Blaise Pascal's
`-.___.-' birth (today) all your programs will run at half speed.


 
Reply With Quote
 
 
 
 
Shashank Date
Guest
Posts: n/a
 
      08-31-2003

"Tom Felker" <(E-Mail Removed)> wrote in message
> Does anyone know a way to do backtick interpolation while protecting the
> command's arguments from the shell, or bypassing the shell entirely?


I am not sure that I understand what you mean by "bypassing the shell",
but will this work for you:

a="%!(*"
%x{echo #{a}}

> writing a script to rename badly named music files, and I have to pass the
> bad name to vorbiscomment and read it's output.


What is a "vorbiscomment" ?

> Apparently Kernel::` is a method, but I can't figure out how to call it
> with my own arguments. Is there a non-punctuation name for it? This


Again, I do not understand this "call with my own arguments" part. Is this
some *ix lingo ? Pardon my ignorance.

> would only be useful if it could accept an argument list as an array and
> not use the shell, as Kernel::system does.


At least on Windows, both system and backtick use the shell...I think

> Thanks,
> --
> Tom Felker, <(E-Mail Removed)>


HTH,
-- shanko



 
Reply With Quote
 
Tom Felker
Guest
Posts: n/a
 
      08-31-2003
On Mon, 01 Sep 2003 07:51:55 +0900, Daniel Carrera wrote:

> I'm not sure I understand what you're asking about backtick
> interpolation. Can you give me a simple example of what you'd like the
> backtick to do so I understand beter?


oldName = "02_Ship_At_Sea_(Instrumental).ogg"
tags = Hash.new
`vorbiscomment #{oldName}`.each_line do |line|
key, value = line.split("=", 2)
tags[key.downcase] = value
end
# ...use tags to formulate proper filename and rename

# Errors:
sh: -c: line 1: syntax error near unexpected token `('
sh: -c: line 1: `vorbiscomment 02_Ship_At_Sea_(Instrumental).ogg'
....

If you use system, you can pass the arguments in an array, and the shell
isn't used, so you can have arguments that the shell would barf on.

system("echo !@#$%^&") == ""
system("echo", "!@#$%^&") == "!@#$%^&")

I need a backtick method that works the same way. Having popen work
that way would be nice. As it is, I think it's only possible with
popen("-"), having the child exec in such a way as to not interpolate
the arguments, and reading from that.

--
Tom Felker, <(E-Mail Removed)>
<http://vlevel.sourceforge.net> - Stop fiddling with the volume knob.

ruby -r complex -e 'c,m,w,h=Complex(-0.75,0.136),50,150,100;puts"P6\n#{w}\n#{h}\
n255";(0...h).each{|j|(0...w).each{|i|n,z=0,Comple x(.9*i/w,.9*j/h);while n<=m&&(
z-c).abs<=2;z=z*z+c;n+=1 end;print [10+n*15,0,rand*99].pack("C*")}}'|display
#by Michael Neumann AFAICT

 
Reply With Quote
 
Daniel Carrera
Guest
Posts: n/a
 
      08-31-2003
Try this:

- `vorbiscomment #{oldName}`.each_line do |line|
+ `vorbiscomment "#{oldName}"`.each_line do |line|

The quotes should make the shell interpret the name literally, instead of
seeing the brackets as a token.

Cheers,
Daniel.

On Mon, Sep 01, 2003 at 08:46:33AM +0900, Tom Felker wrote:
> On Mon, 01 Sep 2003 07:51:55 +0900, Daniel Carrera wrote:
>
> > I'm not sure I understand what you're asking about backtick
> > interpolation. Can you give me a simple example of what you'd like the
> > backtick to do so I understand beter?

>
> oldName = "02_Ship_At_Sea_(Instrumental).ogg"
> tags = Hash.new
> `vorbiscomment #{oldName}`.each_line do |line|
> key, value = line.split("=", 2)
> tags[key.downcase] = value
> end
> # ...use tags to formulate proper filename and rename
>
> # Errors:
> sh: -c: line 1: syntax error near unexpected token `('
> sh: -c: line 1: `vorbiscomment 02_Ship_At_Sea_(Instrumental).ogg'
> ....
>
> If you use system, you can pass the arguments in an array, and the shell
> isn't used, so you can have arguments that the shell would barf on.
>
> system("echo !@#$%^&") == ""
> system("echo", "!@#$%^&") == "!@#$%^&")
>
> I need a backtick method that works the same way. Having popen work
> that way would be nice. As it is, I think it's only possible with
> popen("-"), having the child exec in such a way as to not interpolate
> the arguments, and reading from that.
>
> --
> Tom Felker, <(E-Mail Removed)>
> <http://vlevel.sourceforge.net> - Stop fiddling with the volume knob.
>
> ruby -r complex -e 'c,m,w,h=Complex(-0.75,0.136),50,150,100;puts"P6\n#{w}\n#{h}\
> n255";(0...h).each{|j|(0...w).each{|i|n,z=0,Comple x(.9*i/w,.9*j/h);while n<=m&&(
> z-c).abs<=2;z=z*z+c;n+=1 end;print [10+n*15,0,rand*99].pack("C*")}}'|display
> #by Michael Neumann AFAICT
>


--
Daniel Carrera, Math PhD student at UMD. PGP KeyID: 9AF77A88
.-"~~~"-.
/ O O \ ATTENTION ALL PASCAL USERS:
: s :
\ \___/ / To commemorate the anniversary of Blaise Pascal's
`-.___.-' birth (today) all your programs will run at half speed.


 
Reply With Quote
 
Tom Felker
Guest
Posts: n/a
 
      09-01-2003
On Mon, 01 Sep 2003 00:21:11 +0000, Mark J. Reed wrote:

> On Sun, Aug 31, 2003 at 06:00:34PM -0500, Shashank Date wrote:
>> I am not sure that I understand what you mean by "bypassing the shell",

>
> It's simple. When you execute `some command` (or the equivalent
> using %x), what Ruby actually executes is your command interpreter
> ("shell" in Unix-speak), passing it the string between `...`
> to execute. It's up to the shell to split up the command into
> words, handle wildcard expansion (at least on UNIX; the command
> interpreter on Windows leaves that latter duty up to the individual
> commands), etc. The problem is that all this power is a security
> hole because it's easy to trick command interpreters into doing
> ugly things just by passing something nefarious as a "filename".
>
> The original poster mentioned Kernel.system, which is the way to
> execute a command when you don't care about its output.
> If you pass it one long string, Kernel.system will also invoke the
> shell, but if instead you pass it separate arguments for each word of
> the command line, it bypasses the shell and executes the command
> directly. Thus:
>
> system("ps -fp#{$$}") # also invokes the shell
> system('ps', "-fp#{$$}") # doesn't invoke the shell
> psOutput = `ps -fp#{$$}` # invokes the shell
>
> The question is: how do you complete the list, that is, capture the
> command output without involving the shell?
>
> The only solution of which I'm aware is to use popen/exec:
>
> if fd = IO.popen('-') then
> psOutput = fd.readlines.join("\n")
> else
> exec 'ps', "-fp#{$$}"
> end
>
> Of course, you could turn this into a method:
>
> def safeBackticks(*args)
> if fd = IO.popen('-') then
> output = fd.readlines.join("\n")


fd.close #right?

> else
> exec *args
> end
> return output
> end


Thanks, that method is exactly what I'm looking for.

I only wonder why it isn't in Ruby already. Although I personally
couldn't care less, the above can only be done in Windows by calling
CreateProcess() directly. Using quotes only works if the filename doesn't
contain quotes. Escaping it would work, but it's a hack, and dependent on
the shell. (Windows's cmd will expand %VAR%, IIRC.) It's also kind of
weird to have a method whose only name is "`".

ri doesn't say what popen("-") does with no block, though I see
it returns twice like fork(). Sweet.

Have fun,
--
Tom Felker, <(E-Mail Removed)>
<http://vlevel.sourceforge.net> - Stop fiddling with the volume knob.

The ability to monopolize a market is insignificant next to the power of the
source.

 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      09-01-2003
On Mon, Sep 01, 2003 at 07:46:24AM +0900, Tom Felker wrote:
> Apparently Kernel::` is a method, but I can't figure out how to call it
> with my own arguments. Is there a non-punctuation name for it?


You can call it explicitly like this:

Kernel.send(:`, "ls /etc")

However unlike system, backtick doesn't let you pass a line already broken
into arguments:

Kernel.send(:`, "ls", "/etc")
#>> ArgumentError: wrong number of arguments(2 for 1)

so that doesn't help you.

Regards,

Brian.

 
Reply With Quote
 
Jason Creighton
Guest
Posts: n/a
 
      09-01-2003
On Mon, 1 Sep 2003 10:28:40 +0900
Wesley J Landaker <(E-Mail Removed)> wrote:

> On Sunday 31 August 2003 6:26 pm, Mark J. Reed wrote:
> > On Sun, Aug 31, 2003 at 06:00:34PM -0500, Shashank Date wrote:
> > > I am not sure that I understand what you mean by "bypassing the
> > > shell",

>
> > The only solution of which I'm aware is to use popen/exec:
> >
> > if fd = IO.popen('-') then
> > psOutput = fd.readlines.join("\n")
> > else
> > exec 'ps', "-fp#{$$}"
> > end

>
> I believe open3 will do what you want as well:


Yep, open3 will do it for him. It'd be nice if the "stock" popen would
support multiple arg to avoid the shell doing the splitting.

> require 'open3'
> Open3.popen3("cmd","args","go","here","etc") { |in,out,err|

^^
Syntax error here

'in' is a Ruby keyword (I think for the 'for x in y' construct.)

But other than that, the example should work.

Jason Creighton
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments