How to delete a non-empty directory using the Dir class? - 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.

Related

How can I create a file on my desktop from a Ruby script?

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

looping files with bash

I'm not very good in shell scripting and would like to ask you some question about looping of files big dataset: in my example I have alot of files with the common .pdb extension in the work dir. I need to loop all of them and i) to print name (w.o pdb extension) of each looped file and make some operation after this. E.g I need to make new dir for EACH file outside of the workdir with the name of each file and copy this file to that dir. Below you can see example of my code which are not worked- it's didn't show me the name of the file and didn't create folder for each of them. Please correct it and show me where I was wrong
#!/bin/bash
# set the work dir
receptors=./Receptors
for pdb in $receptors
do
filename=$(basename "$pdb")
echo "Processing of $filename file"
cd ..
mkdir ./docking_$filename
done
Many thanks for help,
Gleb
If all your files are contained within the .Repectors folder, you can loop each of them like so:
#!/bin/bash
for pdb in ./Receptors/*.pdb ; do
filename=$(basename "$pdb")
filenamenoextention=${filename/.pdb/}
mkdir "../docking_${filenamenoextention}"
done
Btw:
filenamenoextention=${filename/.pdb/}
Does a search replace in the variable $pdb. The syntax is ${myvariable/FOO/BAR}, and replaces all "FOO" substrings in $myvariable with "BAR". In your case it replaces ".pdb" with nothing, effectively removing it.
Alternatively, and safer (in case $filename contains multiple ".pdb"-substrings) is to remove the last four characters, like so: filenamenoextention=${filename:0:-4}
The syntax here is ${myvariable:s:e} where s and e correspond to numbers for the start and end index (not inclusive). It also let's you use negative numbers, which are offsets from the end. In other words: ${filename:0:-4} says: extract the substring from $filename starting from index 0, until you reach fourth-to-the-last character.
A few problems you have had with your script:
for pdb in ./Receptors loops only "./Receptors", and not each of the files within the folder.
When you change to parent directory (cd ..), you do so for the current shell session. This means that you keep going to the parent directory each time. Instead, you can specify the parent directory in the mkdir call. E.g mkdir ../thedir
You're looping over a one-item list, I think what you wanted to get is the list of the content of ./Receptors:
...
for pdb in $receptors/*
...
to list only file with .pdb extension use $receptors/*.pdb
So instead of just giving the path in for loop, give this:
for pdb in $receptors/*.pdb
To remove the extension :
set the variable ext to the extension you want to remove and using shell expansion operator "%" remove the extension from your filename eg:
ext=.pdb
filename=${filename%${ext}}
You can create the new directory without changing your current directory:
So to create a directory outside your current directory use the following command
mkdir ../docking_$filename
And to copy the file in the new directory use cp command
After correction
Your script should look like:
receptors=./Receptors
ext=.pdb
for pdb in $receptors/*.pdb
do
filename=$(basename "$pdb")
filename=${filename%${ext}}
echo "Processing of $filename file"
mkdir ../docking_$filename
cp $pdb ../docking_$filename
done

Recursively copy file-types from directory tree

I'm trying to find a way to copy all *.exe files (and more, *.dtd, *.obj, etc.) from a directory structure to another path.
For example I might have:
Code
\classdirA
\bin
\classA.exe
\classdirB
\bin
\classB.exe
\classdirC
\bin
\classC.exe
\classdirD
\bin
\classD.exe
And I want to copy all *.exe files into a single directory, say c:\bins
What would be the best way to do this?
Constraints for my system are:
Windows
Can be Perl, Ruby, or .cmd
Anyone know what I should be looking at here?
Just do in Ruby, using method Dir::glob :
# this will give you all the ".exe" files recursively from the directory "Code".
Dir.glob("c:/Code/**/*.exe")
** - Match all directories recursively. This is used to descend into the directory tree and find all files in sub-directories of the current directory, rather than just files in the current directory. This wildcard is explored in the example code.
* - Match zero or more characters. A glob consisting of only the asterisk and no other characters or wildcards will match all files in the current directory. The asterisk is usually combined with a file extension, if not more characters to narrow down the search.
Nice blog Using Glob with Directories.
Now to copy the files to your required directory, you need to look into the method, FileUtils.cp_r :
require 'fileutils'
FileUtils.cp_r Dir.glob("c:/Code/**/*.exe"), "c:\\bins"
I just have tested, that FileUtils.cp method will also work, in this case :
require 'fileutils'
FileUtils.cp Dir.glob("c:/Code/**/*.exe"), "c:\\bins"
My preference here is to use ::cp method. Because Dir::glob is actually collecting all the files having .exe extensions recursively, and return them as an array. Now cp method is enough here, now just taking each file from the array and coping it to the target file.
Why I am not liking in such a situation, the method ::cp_r ?
Okay, let me explain it here also. As the method name suggests, it will copy all the files recursively from the source to target directory. If there is a need to copy specific files recursively, then ::cp_r wouldn't be able to do this by its own power ( as it can't do selections by itself, which ::glob can do ). Thus in such a situation, you have to give it the specific file lists, it would then copy then to the target directory. If this is the only task, I have to do, then I think we should go with ::cp, rather than ::cp_r.
Hope my explanation helps.
From cmd command line
for /r "c:\code" %f in (*.exe) do copy "%~ff" "c:\bins"
For usage inside a batch file, double the percent signs (%% instead of %)
Windows shell (cmd) command:
for /r code %q in (*.exe) do copy "%q" c:\bin
Double the % characters if you place this in a batch file.

Delete hidden files in Ruby

Does anyone know how to delete all files in a directory with Ruby. My script works well when there are no hidden files but when there are (i.e .svn files) I cannot delete them and Ruby raises the Errno::ENOTEMPTY error.
How do I do that ?
If you specifically want to get rid of your svn files, here's a script that will do it without harming the rest of your files:
require 'fileutils'
directories = Dir.glob(File.join('**','.svn'))
directories.each do |dir|
FileUtils.rm_rf dir
end
Just run the script in your base svn directory and that's all there is to it (if you're on windows with the asp.net hack, just change .svn to _svn).
Regardless, look up Dir.glob; it should help you in your quest.
.svn isn't a file, it's a directory.
Check out remove_dir in FileUtils.
It probably has nothing to do with the fact, that .svn is hidden. The error suggest, that you are trying to delete a non empty directory. You need to delete all files within the directory before you can delete the directory.
Yes, you can delete (hiden) directory using FileUtils.remove_dir path.
I happend to just write a script to delete all the .svn file in the directory recursively. Hope it helps.
#!/usr/bin/ruby
require 'fileutils'
def svnC dir
d = Dir.new(dir)
d.each do |f|
next if f.eql?(".") or f.eql?("..")
#if f is directory , call svnC on it
path = dir + "/" + "#{f}"
if File.stat(path).directory?
if f.eql?(".svn")
FileUtils.remove_dir path
else
svnC path
end
end
end
end
svnC FileUtils.pwd
As #evan said you can do
require 'fileutils'
Dir.glob('**/.svn').each {|dir| FileUtils.rm_rf(dir) }
or you can make it a one liner and just execute it from the command line
ruby -e "require 'fileutils'; Dir.glob('**/.svn').each {|dir| FileUtils.rm_rf(dir) }"

What a safe and easy way to delete a dir in Ruby?

I'd like to delete a directory that may or may not contain files or other directories. Looking in the Ruby docs I found Dir.rmdir but it won't delete non-empty dir. Is there a convenience method that let's me do this? Or do I need to write a recursive method to examine everything below the directory?
require 'fileutils'
FileUtils.rm_rf(dir)
A pure Ruby way:
require 'fileutils'
FileUtils.rm_rf("/directory/to/go")
If you need thread safety: (warning, changes working directory)
FileUtils.rm_rf("directory/to/go", :secure=>true)
If some looking for answer on #ferventcoder comment -
Just a note, I found that with Windows and Ruby 1.9.3 (at least) FileUtils.rm_rf will follow links (symlinks in this case) and delete those files and folders as well. This was found based on creating a symlink with CreateSymbolicLinkW and then running FileUtils.rm_rf against a parent directory the symlinks are in. Not exactly expected behavior.
– ferventcoder
Safest way is to iterate path and delete it manually.
def rec_del(path):
if path is file call FileUtils.rm_rf - it is safe to delete even in windows
if dir call Dir.rmdir which will succeed for empty dir and dir symlink. else will get ENOTEMPTY for regular non empty dir.
iterate the dir and call rec_del for each item.
now call again Dir.rmdir which will succeed
The laziest way is:
def delete_all(path)
`rm -rf "#{path}"`
end

Resources