Getting the executed command from FileUtils?

2019-06-28 02:20发布

When you pass the :verbose flag to a FileUtils command, the command gets printed to STDOUT. Is there a way to capture the command so it can be logged or used elsewhere?

标签: ruby rubygems
2条回答
Evening l夕情丶
2楼-- · 2019-06-28 03:09

If you look at the source for FileUtils it uses the following method for doing its verbose output:

def fu_output_message(msg)   #:nodoc:
  @fileutils_output ||= $stderr
  @fileutils_label  ||= ''
  @fileutils_output.puts @fileutils_label + msg
end

i.e. it is writing the messages to @fileutils_output and by default it is using $stderr. There doesn't seem to be a method to alter @fileutils_output but you could add one:

module FileUtils
  def FileUtils.fileutils_output=(new_out)
    @fileutils_output = new_out
  end
end

Then if you wanted to capture the commands into a file you could do:

my_fu_log = open('fu_log.log', 'w')
FileUtils.fileutils_output = my_fu_log
# FileUtils operations with :verbose => true here
my_fu_log.close
FileUtils.fileutils_output = $stderr # restore writing to stderr if you want

or if you wanted to get them in a string you could do:

log = StringIO.new
FileUtils.fileutils_output = log
# FileUtils operations with :verbose => true here
# commands are in log.string 

Also, there is a module FileUtils::Verbose which basically includes FileUtils (so has all the same methods) but defaults the options to :verbose => true so if you wanted to capture lots of commands you could use this instead of specifying the option each time. (you would need to add the fileutils_output= method to this module in the same way as above.)

Alternatives

As Joshua says in the comments below, an alternative is to reassign $stderr but as he says this does mean that everything written to stderr (not just by FileUtils) is redirected. If all the FileUtils operations are happening in one go without anything else in between then this might not be an issue. So something along the lines of:

orig_stderr = $stderr # keep reference to original stderr
$stderr = my_fu_log
# use FileUtils here
$stderr = orig_stderr # restore stderr

Finally, you could reopen FileUtils and override fu_output_message(msg) itself if you need more control.

查看更多
Ridiculous、
3楼-- · 2019-06-28 03:16

To add to Mike's answer (since I can't comment), I created this wrapper def if you want to get the output as a string:

def fileutil_out
    out = StringIO.new
    FileUtils.fileutils_output = out
    yield
    return out.string
end

mylog.info fileutil_out { FileUtils.chmod_R(0664, 'file.txt', :verbose => isVerbose) }

I ended up not using it since I wanted to revert back to @fileutils_output ||= $stderr afterwards.

查看更多
登录 后发表回答