Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby escape ARGV argument or string as argument to shell command

Ok this is driving me crazy:

`ls #{"/media/music/Miles Davis"}`

fails because of the space between "Miles" and "Davis"

Say I write a ruby script and a user passes file path as an argument. How do I escape it and feed to a shell-out command. Yes, yes, I know, shelling out should be avoided. But this is a contrived example, I still need this.

I would do system("ls", ARGV[0]), but it doesn't return the stdout output of ls as a string, which is what backticks do well.

How do escape whatever you insert in a shellout?

like image 967
ulver Avatar asked Aug 03 '11 04:08

ulver


2 Answers

Use require 'shellwords' and Shellwords.escape, which will fix this sort of stuff for you:

http://apidock.com/ruby/Shellwords/shellescape

like image 151
Casper Avatar answered Nov 19 '22 02:11

Casper


Stay away from building shell strings

This is a fine vector for arbitrary code execution.

In this case, you could use popen, which does the escaping for you, e.g.:

#!/usr/bin/env ruby
IO.popen(['printf', 'a b']) do |f|
  puts f.read
end

This outputs:

a b

just as if we had run on the terminal:

/usr/bin/printf 'a b'

If a b hadn't been escaped, we wouldn't get a b as expected, because running an unquoted:

/usr/bin/printf a b

in the terminal gives:

a/usr/bin/printf: warning: ignoring excess arguments, starting with ‘b’

Tested in Ubuntu 20.02, Ruby 2.6.