CJW
CJW

Reputation: 342

Getting word count of a file in Ruby and not open to Command Injection

How do I get the line count of a file into a variable in Ruby using the Unix command wc for speed for very large files whilst making sure that it's safe from command injection using either open3, system or something similar to achieve the same output as `wc -l < "#{file_path}".to_i`

Upvotes: 0

Views: 92

Answers (2)

Ivan Olshansky
Ivan Olshansky

Reputation: 969

If you prefer to use native shell command and the only thing you want is to escape file_path, there is a Shellwords class in the standard library.

It's very easy to use it in your task:

require 'shellwords'

`wc -l < #{Shellwords.escape(file_path)}`.to_i

Upvotes: 1

mu is too short
mu is too short

Reputation: 434755

Probably the easiest is to use Open3::capture2:

output, status = Open3::capture2('wc', '-l', file_path)

Then you can check status and deal with errors as needed and since output should be something like " 2342 file_path\n", you can get the count with a simple #to_i call:

line_count = output.to_i

If you don't care about error handling (which would never happen in real life):

line_count = Open3::capture2('wc', '-l', file_path).first.to_i

No shell will be involved, no command injection issues.

However, this assumes that the first wc in your PATH is the wc you want to use so you might want to be more specific:

# Or ensure that your PATH environment variable is sensible.
output, status = Open3::capture2('/usr/bin/wc', '-l', file_path)

This also assumes that you want the users to be able to read any file that your process can; if that's not the case then you'd need to blacklist/whitelist file_path to make sure it is something that they're supposed to be able to read.

Of course, if you're going to all this trouble you might as well open the file and count the lines yourself with a couple lines of Ruby:

# Or some variation on this and a `rescue` to catch exceptions.
line_count = File.open('Gemfile') { |fp| fp.each_line.count }

Upvotes: 1

Related Questions