41

So I found this question on here, but I'm having an issue with the output and how to handle it with an if statement. This is what I have, but it's always saying that it's true even if the word monitor does not exist in the file

if File.readlines("testfile.txt").grep(/monitor/)
  do something
end

Should it be something like == "nil"? I'm quite new to ruby and not sure of what the outputs would be.

1
  • 2
    Note: Using readlines can really cause problems if the file is larger than the available memory. See "Why is slurping a file bad?" for more information. Commented Dec 11, 2014 at 22:27

5 Answers 5

69

I would use:

if File.readlines("testfile.txt").grep(/monitor/).any?

or

if File.readlines("testfile.txt").any?{ |l| l['monitor'] }

Using readlines has scalability issues though as it reads the entire file into an array. Instead, using foreach will accomplish the same thing without the scalability problem:

if File.foreach("testfile.txt").grep(/monitor/).any?

or

if File.foreach("testfile.txt").any?{ |l| l['monitor'] }

See "Why is "slurping" a file not a good practice?" for more information about the scalability issues.

Sign up to request clarification or add additional context in comments.

7 Comments

+1 for any?, since this will end as soon as it finds the first match instead of processing every line just to see if any matched.
Keep in mind that this is not idempotent. Running it twice in a row will return true on the first run and false on the second. You need to rewind the file before running it again.
There is no need to rewind. readlines will open and close the file automatically so it always starts at the beginning and reads to the end.
Again with the +1 for any?, though to quickly clarify, the approach to return as soon as you have a match is any? { ... } rather than grep(...).any?. Learned this the hard way, should pay closer attention :)
@SRack You're not alone. I did the same thing. I edited the answer to put the best method first and then show the alternatives with reasonings about why each alternative is inferior to the top method.
|
39

Enumerable#grep does not return a boolean; it returns an array (how would you have access to the matches without passing a block otherwise?).

If no matches are found it returns an empty array, and [] evaluates to true. You'll need to check the size of the array in the if statement, i.e.:

if File.readlines("testfile.txt").grep(/monitor/).size > 0
  # do something
end

The documentation should be your first resource for questions like this.

4 Comments

Thanks for this post. you have help me a lot with that. but I was wondering if I need to search for a path?
@MZaragoza: Depends on what kind of path. I'm sure if you search for regular expressions to match a path you'll find quite a few examples.
I am looking for a string in a file that looks like "/www/assests/2015/09/18/someimage.png" the problem is that there are other images names 'someimage.png' in other directories
For paths, you may want to use a regular expression in grep. For eg ; File.readlines("/home/#{os_user}/.bash_profile").grep(%r{JAVA_HOME=\/opt\/Oracle\/jdk}).empty?
7

Grep will give you an array of all found 'monitor's. But you don't want an array, you want a boolean: is there any 'monitor' string in this file? This one reads as little of the file as needed:

if File.open('test.txt').lines.any?{|line| line.include?('monitor')}
  p 'do something'
end

readlines reads the whole file, lines returns an enumerator which does it line by line.

update

#lines are deprecated, Use #each_line instead

  if File.open('test.txt').each_line.any?{|line| line.include?('monitor')}
    p 'do something'
  end

Comments

0

if anyone is looking for a solution to display last line of a file where that string occurs just do

File.readlines('dir/testfile.txt').select{|l| l.match /monitor/}.last 

example

file:

monitor 1
monitor 2
something else

you'll get

monitor 2

Comments

0

I generally skip ruby for the command-line utilities as they tend to be faster.

`grep "monitor" "testfile.txt" > /dev/null`
$?.success #=> true if zero exit status, false otherwise.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.