I am trying to use a script to change the working directory using Dir.chdir
This works:
dirs = ['//servername/share','//servername2/share']
dirs.each do |dir|
Dir.chdir dir
end
If I put the above share information into a text file (each share on a new line) and try to load:
File.foreach("shares.txt") {|dir|
Dir.chdir dir
}
I get this error:
'chdir': No such file or directory - //servername/share (Errno::ENOENT)
How can I read the shares from a text file and change to that directory? Is there a better way to do this?
Try
Dir.chdir dir.strip
or
Dir.chdir dir.chomp
Reason:
With File.foreach you get lines including a newlines (\n).
strip will delete leading and trailing spaces, chomp will delete trailing newlines.
Another possibility: In your example you use absolute paths. This should work.
If you use relative paths, then check, in which directory you are (you change it!). To keep the directory you may use the block-version of Dir.chdir.
Related
I am trying to read a list of baby names from the year 1880 in CSV format. My program, when run in the terminal on OS X returns an error indicating yob1880.txt doesnt exist.
No such file or directory # rb_sysopen - /names/yob1880.txt (Errno::ENOENT)
from names.rb:2:in `<main>'
The location of both the script and the text file is /Users/*****/names.
lines = []
File.expand_path('../yob1880.txt', __FILE__)
IO.foreach('../yob1880.txt') do |line|
lines << line
if lines.size >= 1000
lines = FasterCSV.parse(lines.join) rescue next
store lines
lines = []
end
end
store lines
If you're running the script from the /Users/*****/names directory, and the files also exist there, you should simply remove the "../" from your pathnames to prevent looking in /Users/***** for the files.
Use this approach to referencing your files, instead:
File.expand_path('yob1880.txt', __FILE__)
IO.foreach('yob1880.txt') do |line|
Note that the File.expand_path is doing nothing at the moment, as the return value is not captured or used for any purpose; it simply consumes resources when it executes. Depending on your actual intent, it could realistically be removed.
Going deeper on this topic, it may be better for the script to be explicit about which directory in which it locates files. Consider these approaches:
Change to the directory in which the script exists, prior to opening files
Dir.chdir(File.dirname(File.expand_path(__FILE__)))
IO.foreach('yob1880.txt') do |line|
This explicitly requires that the script and the data be stored relative to one another; in this case, they would be stored in the same directory.
Provide a specific path to the files
# do not use Dir.chdir or File.expand_path
IO.foreach('/Users/****/yob1880.txt') do |line|
This can work if the script is used in a small, contained environment, such as your own machine, but will be brittle if it data is moved to another directory or to another machine. Generally, this approach is not useful, except for short-lived scripts for personal use.
Never put a script using this approach into production use.
Work only with files in the current directory
# do not use Dir.chdir or File.expand_path
IO.foreach('yob1880.txt') do |line|
This will work if you run the script from the directory in which the data exists, but will fail if run from another directory. This approach typically works better when the script detects the contents of the directory, rather than requiring certain files to already exist there.
Many Linux/Unix utilities, such as cat and grep use this approach, if the command-line options do not override such behavior.
Accept a command-line option to find data files
require 'optparse'
base_directory = "."
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on('-d', '--dir NAME', 'Directory name') {|v| base_directory = Dir.chdir(File.dirname(File.expand_path(v))) }
end
IO.foreach(File.join(base_directory, 'yob1880.txt')) do |line|
# do lines
end
This will give your script a -d or --dir option in which to specify the directory in which to find files.
Use a configuration file to find data files
This code would allow you to use a YAML configuration file to define where the files are located:
require 'yaml'
config_filename = File.expand_path("~/yob/config.yml")
config = {}
name = nil
config = YAML.load_file(config_filename)
base_directory = config["base"]
IO.foreach(File.join(base_directory, 'yob1880.txt')) do |line|
# do lines
end
This doesn't include any error handling related to finding and loading the config file, but it gets the point across. For additional information on using a YAML config file with error handling, see my answer on Asking user for information, and never having to ask again.
Final thoughts
You have the tools to establish ways to locate your data files. You can even mix-and-match solutions for a more sophisticated solution. For instance, you could default to the current directory (or the script directory) when no config file exists, and allow the command-line option to manually override the directory, when necessary.
Here's a technique I always use when I want to normalize the current working directory for my scripts. This is a good idea because in most cases you code your script and place the supporting files in the same folder, or in a sub-folder of the main script.
This resets the current working directory to the same folder as where the script is situated in. After that it's much easier to figure out the paths to everything:
# Reset working directory to same folder as current script file
Dir.chdir(File.dirname(File.expand_path(__FILE__)))
After that you can open your data file with just:
IO.foreach('yob1880.txt')
I have a command line program that asks the user a set of questions and stores them in a file. The only problem is, I need it to create a new file and it won't.
Here is what I have tried:
File.open("path/to/file", "w")and File.open("path/to/file", "w+")
Both times I get this error
in 'initialize': No such file or directory # rb_sysopen - path/to/file (Errno::ENOENT)
Here is my current code:
File.open("path/to/file", "w") { |f| f.write(array.join("\n")) }
When someone writes path/to/file in a blog post or documentation, they don't intend for you to literally write path/to/file in your code. The point is that you need to edit that string to actually have the real path to your file, either as a relative path or an absolute path.
You said you are getting this error from the Ruby interpreter:
No such file or directory # rb_sysopen - path/to/file (Errno::ENOENT)
This means that in the current working directory, there is no directory named "path", or if there is a directory named "path", then it doesn't have a child directory named "to".
You could solve the immediate problem by running mkdir -p path/to, but that would be weird. It is better to just write an appropriate path in your code, pointing to a directory that already exists. Try changing the path to simply be output.txt (without any slashes) and see how that works.
Ensure you are using an absolute path, and if so, make sure the directory you want to store the file in is missing. Try creating it first:
require 'fileutils'
FileUtils.mkdir_p '/path/to'
File.open('/path/to/file', 'w') { ... }
I'm building a webcrawler and I want it to output to a new file that is timestamped. I've completed what I thought would be the more difficult part but I cannot seem to get it to save to the desktop.
Dir.chdir "~/Desktop"
dirname = "scraper_out"
filename = "#{time}"
Dir.mkdir(dirname) unless File.exists?(dirname)
Dir.chdir(dirname)
File.new(filename, "w")
It errors out on the first line
`chdir': No such file or directory # dir_chdir - ~/Desktop
I've read the documentation on FileUtils, File and cannot seem to find where people change into nested directories from the root.
Edit: I don't think FileUtils understands the ~.
~/ is not recognized by Ruby in this context.
Try:
Dir.chdir ENV['HOME']+"/Desktop"
This might help you
Create a file in a specified directory
I'm trying to do a simple regex to grab specific text out of a bunch of text files in a directory. The code I'm using is below:
input_dir = File.join('path/to/file/dir/', "*.txt")
Dir.glob(input_dir) do |file|
if /\.txt$/i.match file
File.open(file, "r") do |_file|
/==BEGIN==(.*)==END==/.match _file.read
puts $1
end
end
end
That works for exactly 1 of the files in the directory, but all other files return nil. Am I missing something here?
Hard to guess with so little data, but could it be that in most files (except one), ==BEGIN== and ==END== are on different lines?
Does /==BEGIN==(.*)==END==/m.match _file.read change anything? The /m modifier allows the dot to also match newlines in Ruby.
Dir.delete("/usr/local/var/lib/trisul/CONTEXT0/meters/oper/SLICE.9stMxh")
causes this error:
Directory not empty - /usr/local/var/lib/trisul/CONTEXT0/meters/oper/SLICE.9stMxh
How to delete a directory even when it still contains files?
Is not possible with Dir (except iterating through the directories yourself or using Dir.glob and deleting everything).
You should use
require 'fileutils'
FileUtils.rm_r "/usr/local/var/lib/trisul/CONTEXT0/meters/oper/SLICE.9stMxh"
When you delete a directory with the Dir.delete, it will also search the subdirectories for files.
Dir.delete("/usr/local/var/lib/trisul/CONTEXT0/meters/oper/SLICE.9stMxh")
If the directory was not empty, it will raise Directory not empty error. For that ruby have FiltUtils.rm_r method which will delete the directory no matter what!
require 'fileutils'
FileUtils.rm_r "/usr/local/var/lib/trisul/CONTEXT0/meters/oper/SLICE.9stMxh"
I use bash directly with the system(*args) command like this:
folder = "~/Downloads/remove/this/non/empty/folder"
system("rm -r #{folder}")
It is not really ruby specific but since bash is simpler in this case I use this frequently to cleanup temporary folders and files. The rm command just removes anything you give it and the -r flag tells it to remove files recursively in case the folder is not empty.