I am facing a certain problem while trying to open files from a directory ( the directory is provided on the command line )
My code is as follows:
require 'optparse'
OptionParser.new do |opts|
opts.banner = "Usage: rubyfile.rb [options]"
options[:c] = ""
opts.on( '-c', '--dir DILE', "Specify Directory with input files" ) do |e|
options[:c] = e
end
options[:o] = ""
opts.on( '-o', '--dir DILE', "Specify Output file" ) do |f|
options[:c] = f
end
end.parse!
out_file = File.open( options[:o], "a" )
dir_open = Dir.open( options[:c] )
Dir.foreach(dir_open) do | in_file |
next if File.directory? in_file
if( in_file.include? ".txt" )
input_file = File.open( in_file, "r" )
File.foreach(input_file).with_index do | line, line_s |
puts line
end
end
end
If I try to print out the file names using puts in_file, it works. But when I try to open the file and dump out its contents, it does not.
I know I am missing something here not able to pinpoint what it is though.
With this chunk right here:
input_file = File.open( in_file, "r" )
File.foreach(input_file).with_index do | line, line_s |
puts line
end
You could instead write File.readlines(in_file).each { |f| puts f }
File.readlines will return an array where each element is a line of the text.
Related
I'm trying this script to rename a series of files with unwanted characters:
$stdout.sync
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir['*'].each do |file|
# Skip directories
next unless File.file?(file)
old_name = File.basename(file,'.*')
if old_name.include?(search)
# Are you sure you want gsub here, and not sub?
# Don't use `old_name` here, it doesn't have the extension
new_name = File.basename(file).gsub(target,replace)
File.rename( file, new_path )
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
I would like to be able to pass as a prompt argument the path of the directory that contains the files to be renamed, and then I modified the script as follows:
$stdout.sync
path = ARGV[0]
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir[path].each do |file|
# Skip directories
next unless File.file?(file)
old_name = File.basename(file,'.*')
if old_name.include?(search)
# Are you sure you want gsub here, and not sub?
# Don't use `old_name` here, it doesn't have the extension
new_name = File.basename(file).gsub(target,replace)
File.rename( file, new_path )
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
get this error message:
renamefiles.rb:3:in `gets': Is a directory # io_fillbuf - fd:7
why?
When you pass an argument such that ARGV is populated the ruby interpreter will assume you mean Kernel#gets which expects a filename.
You should be able to fix this by using STDIN.gets so you would have
print "Enter the file search query: "; search = STDIN.gets.chomp
print "Enter the target to replace: "; target = STDIN.gets.chomp
print " Enter the new target name: "; replace = STDIN.gets.chomp
I have refined the code so that the file extension is not changed, and the directories are also renamed.
I have two problems left to solve:
-the passage of the path from argv (the path is not correctly recognized)
-I would like to recursively rename, even files in directories
path = ARGV[0]
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir::chdir('/Users/dennis/Documents/test/daRinominare')
Dir['*'].each do |file|
#puts file
if Dir.exist?(file)
directoryList = file
old_name = File.basename(file)
new_name = old_name.gsub(target,replace)
File.rename( file, new_name)
end
next unless File.file?(file)
old_name = File.basename(file,'.*')
extension = File.extname(file)
if old_name.include?(search)
new_name = old_name.gsub(target,replace) + extension
File.rename( file, new_name)
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
Kernel.gets reads from ARGF, which acts as an aggregate IO to read from the files named in ARGV, unless ARGV is empty in which case ARGF reads from $stdin. ARGF.gets will generate errors like EISDIR and ENOENT if ARGV has entries which are paths to directories or paths that don't exist.
If you want to read user input, use $stdin.gets
(The difference between $stdin and STDIN: The constant STDIN is the process standard input stream, and is the initial value of the variable $stdin which can be reassigned to change the source used by library methods; see globals. I use $stdin unless I need to change $stdin and also use STDIN for another purpose.)
I'm writing a little script in Ruby that removes comments from Ruby files:
#!/usr/bin/ruby
def uncomment(file)
File.readlines(file).each do |line|
if line =~ /(^\s*#|^\t*#)(?!\!).*/
puts line + " ==> this is a comment"
#todo: remove line from the file
end
end
end
puts "Fetching all files in current directory and uncommenting them"
# fetching all files
files = Dir.glob("**/**.rb")
# parsing each file
files.each do |file|
#fetching each line of the current file
uncomment file
end
I am stuck on how to remove these lines that match the regex in the #todo section, it would be great if someone could help!
change:
def uncomment(file)
File.readlines(file).each do |line|
if line =~ /#(?!\!).+/
puts line + " ==> this is a comment"
#todo: remove line from the file
end
end
end
to:
def uncomment(file)
accepted_content = File.readlines(file).reject { |line| line =~ /#(?!\!).+/ }
File.open(file, "w") { |f| accepted_content.each { |line| f.puts line } }
end
You would be reading the accepted lines into an array(accepted_content), and writing back that array into the file
I would do this by creating a temporary file:
open('tmp', 'w') do |tmp|
File.open(file).each do |line|
tmp << line unless line =~ /#(?!\!).+/
end
end
File.rename('tmp', file)
I have a simple Ruby script that is building a list of files from an array of strings, so I have a method a bit like this:
def initialize( rootpath, name )
#content = ""
intermission = ""
if ( ! (rootpath[-1] == "/" || name[0] == "/" ))
intermission="/"
end
#path= "#{rootpath}#{intermission}#{name}"
print "Open JavascriptFile from #{#path}"
if (! File.exists? #path)
print "File does not exist!"
end
File.open( #path ).each do |line|
#content << line
end
end
This is called along the lines of:
files= ['alice.js', 'bob.js', 'claire.js', 'dave.js']
basepath= "/home/glenatron/projects/myJSProject/"
files.each do |filename|
myLoader.new( basepath, filename )
end
When I load in my classes from IRB and run this I get:
Open JavascriptFile from /home/glenatron/projects/myJSProject/alice.js
File does not exist!
Errno::ENOENT: No such file or directory - /home/glenatron/projects/myJSProject/alice.js
As I understand it, this means that the file does not exist.
However not only does the file definitely exist, in IRB I can paste the exact same path and see it's content - a simple File.open("/home/glenatron/projects/myJSProject/alice.js").each { | line | print line } reveals the complete content of the file. So why can I do this from a direct command line request and not from my Ruby class? Is it trying to read a local path instead of the full path I am passing it?
Guard the File.open .. lines with else block:
if (! File.exists? #path)
print "File does not exist!"
else # <---
File.open( #path ).each do |line|
#content << line
end
end # <----
or return earlier in the if block:
if (! File.exists? #path)
print "File does not exist!"
return
endif
Otherwise, the code always try to open the file, even if it does not exist.
Use File::join to join the path components:
File.join("/home/glenatron/projects/myJSProject/", "alice.js")
# => "/home/glenatron/projects/myJSProject/alice.js"
File.join("/home/glenatron/projects/myJSProject", "alice.js")
# => "/home/glenatron/projects/myJSProject/alice.js"
Edit to bring the solution ( in the comments ) into the answer:
To find the exact path, use p #path - this revealed that the path that was trying to open looked like this when it failed: /home/glenatron/projects/myJSProject/alice.js\r which was causing the problem. A simple #path.strip! resolved it once this was clear.
From your code shown in the question,
looks like an end instead of an else, e.g.
if (! File.exists? #path)
print "File does not exist!"
end # <------------ This wasn't valid
File.open( #path ).each do |line|
#content << line
end
end
should be
if (! File.exists? #path)
print "File does not exist!"
else
File.open( #path ).each do |line|
#content << line
end # THIS end is valid as it ends a `.each` block
end
f = File.open("/test/serverlist.txt", "r")
list = f.readlines
list.each do|servers|
File.open('/test/results.txt','w') do |b|
servers.each do |p|
r = `ping -n 1 #{p}`
b.puts r
end
end
It reads the serverlist file, and returns a string. The serverlist file contains the following IP addresses:
192.168.150.254
192.168.120.2
Are you looking to read each line from the file and then do something with like this.
fout = File.open('/test/results.txt','w')
File.open("/test/serverlist.txt", "r").each_line do |server|
server.chomp!
r = `ping -n 1 #{server}`
fout.puts r
end
I don't think you will need to iterate over the server line itself, and with a few style mods added and ping(1) arguments changed, I would suggest...
open 'serverlist.txt', 'r' do |f|
open '/tmp/results.txt', 'w' do |b|
f.readlines.each do |server|
b.puts `ping -c 1 -t 1 #{server}`
end
end
end
Just use b.write in place of b.puts
if you're using linux you could just go for
File.open("serverlist.txt").each { |addy| `echo "#{`ping -c 1 #{addy}`}" >> result.txt` }
and be done with it
well .. maybe add
`echo "# server-availability" > result.txt`
before the above line so the file gets reset every time you call this
Since:
irb --help
Usage: irb.rb [options] [programfile] [arguments]
I know I can pass arguments to ARGV if I include a programfile
eg:
irb test.rb A B C
where test.irb is simply "p ARGV"
produces:
["a", "b", "c"]
Making programfile be con in DOS... I can do following
irb con A B C
con(main):001:0> ARGV
produces:
ARGV
=> ["A", "B", "C"]
but this is system dependent and has the side effect of echoing input :-(
What i really like is something like
irb -- a b c
BTW: I know I can set ARGV inside irb but I my intention is to alias special == irb -rSpecialLibrary" so I can do something like:
special A B C
<input goes here>
Any suggestions?
Looking at the source of the irb executable:
#!/usr/bin/env ruby
require "irb"
if __FILE__ == $0
IRB.start(__FILE__)
else
# check -e option
if /^-e$/ =~ $0
IRB.start(__FILE__)
else
IRB.setup(__FILE__)
end
end
The at the source of the IRB module:
# File lib/irb/init.rb, line 15
def IRB.setup(ap_path)
IRB.init_config(ap_path)
IRB.init_error
IRB.parse_opts
IRB.run_config
IRB.load_modules
unless #CONF[:PROMPT][#CONF[:PROMPT_MODE]]
IRB.fail(UndefinedPromptMode, #CONF[:PROMPT_MODE])
end
end
Down to parse_opts, our problem method:
# File lib/irb/init.rb, line 126
def IRB.parse_opts
load_path = []
while opt = ARGV.shift
case opt
when "-f"
#CONF[:RC] = false
when "-m"
#CONF[:MATH_MODE] = true
when "-d"
$DEBUG = true
when /^-r(.+)?/
opt = $1 || ARGV.shift
#CONF[:LOAD_MODULES].push opt if opt
when /^-I(.+)?/
opt = $1 || ARGV.shift
load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt
when '-U'
set_encoding("UTF-8", "UTF-8")
when /^-E(.+)?/, /^--encoding(?:=(.+))?/
opt = $1 || ARGV.shift
set_encoding(*opt.split(':', 2))
when "--inspect"
#CONF[:INSPECT_MODE] = true
when "--noinspect"
#CONF[:INSPECT_MODE] = false
when "--readline"
#CONF[:USE_READLINE] = true
when "--noreadline"
#CONF[:USE_READLINE] = false
when "--echo"
#CONF[:ECHO] = true
when "--noecho"
#CONF[:ECHO] = false
when "--verbose"
#CONF[:VERBOSE] = true
when "--noverbose"
#CONF[:VERBOSE] = false
when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
opt = $1 || ARGV.shift
prompt_mode = opt.upcase.tr("-", "_").intern
#CONF[:PROMPT_MODE] = prompt_mode
when "--noprompt"
#CONF[:PROMPT_MODE] = :NULL
when "--inf-ruby-mode"
#CONF[:PROMPT_MODE] = :INF_RUBY
when "--sample-book-mode", "--simple-prompt"
#CONF[:PROMPT_MODE] = :SIMPLE
when "--tracer"
#CONF[:USE_TRACER] = true
when /^--back-trace-limit(?:=(.+))?/
#CONF[:BACK_TRACE_LIMIT] = ($1 || ARGV.shift).to_i
when /^--context-mode(?:=(.+))?/
#CONF[:CONTEXT_MODE] = ($1 || ARGV.shift).to_i
when "--single-irb"
#CONF[:SINGLE_IRB] = true
when /^--irb_debug=(?:=(.+))?/
#CONF[:DEBUG_LEVEL] = ($1 || ARGV.shift).to_i
when "-v", "--version"
print IRB.version, "\n"
exit 0
when "-h", "--help"
require "irb/help"
IRB.print_usage
exit 0
when "--"
if opt = ARGV.shfit
#CONF[:SCRIPT] = opt
$0 = opt
end
break
when /^-/
IRB.fail UnrecognizedSwitch, opt
else
#CONF[:SCRIPT] = opt
$0 = opt
break
end
end
if RUBY_VERSION >= FEATURE_IOPT_CHANGE_VERSION
load_path.collect! do |path|
/\A\.\// =~ path ? path : File.expand_path(path)
end
end
$LOAD_PATH.unshift(*load_path)
end
It is hardcoded to take that option as the script name (#CONF[:SCRIPT] = opt). Luckily, this is Ruby. The first idea I had was using a different script to launch IRB that modifies the module first.
~/bin/custom-irb:
#!/usr/bin/env ruby
require 'irb'
module IRB
class << self
# sort of lame way to reset the parts we don't like about
# parse_opts after it does the parts we do like
def parse_opts_with_ignoring_script
arg = ARGV.first
script = $0
parse_opts_without_ignoring_script
#CONF[:SCRIPT] = nil
$0 = script
ARGV.unshift arg
end
alias_method :parse_opts_without_ignoring_script, :parse_opts
alias_method :parse_opts, :parse_opts_with_ignoring_script
end
end
if __FILE__ == $0
IRB.start(__FILE__)
else
# check -e option
if /^-e$/ =~ $0
IRB.start(__FILE__)
else
IRB.setup(__FILE__)
end
end
You can launch this with custom-irb foo bar baz and ARGV will be ['foo', 'bar', 'baz'].
quite strange solution is to create file with variables
# defaults.rb
#a = "hello world"
And
# terminal
=> irb -r defaults.rb
irb=> #a
irb=> "hello world"
You can make a file that modifies ARGV and then use '-r' to include it.
$ echo 'ARGV = ["testing", "1","2","3"]' > ~/blah.rb && irb -r ./blah test.rb
/home/me/blah.rb:1: warning: already initialized constant ARGV
test.rb(main):001:0> require 'pp'
=> true
test.rb(main):002:0* pp ARGV
["testing", "1", "2", "3"]
=> ["testing", "1", "2", "3"]
test.rb(main):003:0>
You could even redirect it to your your ~/.irbrc and leave out the '-r ./blah'.