How to recursively change file permissions only in a ruby script - ruby

I have been using the function FileUtils.chmod_R to recursively change files and directories permissions under a given path but now want to change only the file permissions and leave the directories as they are. Looking at the man page for this function I can't see how to do this and I would prefer not to do this with a bash script. Please can someone tell me if this is possible with the FileUtils.chmod_R function or would I have to write additional code to iterate over every file that exist under a given path (recursive) and then FileUtils.chmod it to the desire permission? I am a ruby newbie so please point me someplace if I am asking anything obvious

You could do something like below - this will change permissions of the list of files matched by Dir.glob.
FileUtils.chmod 0400, Dir.glob('/path/to/dir/**/*')
As mentioned in this thread,
Dir.glob("**/*/") # will return list of all directories
Dir.glob("**/*") # will return list of all files

Related

how to check if file exists in all subdirectories?

How to check if the file exists in all subdirectories within chef recipe (not_if guard).
There is no specific answer other than "write some Ruby code to check what you want". You'll probably want to do a Dir glob and then compare the various outputs but maybe you just need an all? and File.exist?.

sql loader without .dat extension

Oracle's sqlldr defaults to a .dat extension. That I want to override. I don't like to rename the file. When googled get to know few answers to use . like data='fileName.' which is not working. Share your ideas, please.
Error message is fileName.dat is not found.
Sqlloder has default extension for all input files data,log,control...
data= .dat
log= .log
control = .ctl
bad =.bad
PARFILE = .par
But you have to pass filename without apostrophe and dot
sqlloder pass/user#db control=control data=data
sqloader will add extension. control.ctl data.dat
Nevertheless i do not understand why you do not want to specify extension?
You can't, at least in Unix/Linux environments. In Windows you can use the trailing period trick, specifying either INFILE 'filename.' in the control file or DATA=filename. on the command line. WIndows file name handling allows that; you can for instance do DIR filename. at a command prompt and it will list the file with no extension (as will DIR filename). But you can't do that with *nix, from a shell prompt or anywhere else.
You said you don't want to copy or rename the file. Temporarily renaming it might be the simplest solution, but as you may have a reason not to do that even briefly you could instead create a hard or soft link to the file which does have an extension, and use that link as the target instead. You could wrap that in a shell script that takes the file name argument:
# set variable from correct positional parameter; if you pass in the control
# file name or other options, this might not be $1 so adjust as needed
# if the tmeproary file won't be int he same directory, need to be full path
filename=$1
# optionally check file exists, is readable, etc. but overkill for demo
# can also check temporary file does not already exist - stop or remove
# create soft link somewhere it won't impact any other processes
ln -s ${filename} /tmp/${filename##*/}.dat
# run SQL*Loader with soft link as target
sqlldr user/password#db control=file.ctl data=/tmp/${filename##*/}.dat
# clean up
rm -f /tmp/${filename##*/}.dat
You can then call that as:
./scriptfile.sh /path/to/filename
If you can create the link in the same directory then you only need to pass the file, but if it's somewhere else - which may be necessary depending on why renaming isn't an option, and desirable either way - then you need to pass the full path of the data file so the link works. (If the temporary file will be int he same filesystem you could use a hard link, and you wouldn't have to pass the full path then either, but it's still cleaner to do so).
As you haven't shown your current command line options you may have to adjust that to take into account anything else you currently specify there rather than in the control file, particularly which positional argument is actually the data file path.
I have the same issue. I get a monthly download of reference data used in medical application and the 485 downloaded files don't have file extensions (#2gb). Unless I can load without file extensions I have to copy the files with .dat and load from there.

Ruby - Search and collect files in all directorys

I'm trying to search for a certain file type within all directories on my unix system using a ruby script. I understand the following code will search all files ending with .pdf within the current directory:
my_pdfs = Dir['*pdf']
As well as:
my_pdfs = Dir.glob('*.pdf').each do |f|
puts f
end
But how about searching all directories and sub-directories for files with the .pdf extension?
Check out the Find module:
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/find/rdoc/Find.html
Using Dir.glob is less than ideal since globbing doesn't handle recursion nearly as well as something like find.
Also if you're on a *nix box try using the find command. Its pretty amazingly useful for one liners.
Maybe something like:
pdfs=Dir['/**/*.pdf']
?
Not using Linux right now, so don't know if that will work. The ** syntax implies recursive listing.

Ruby (Errno::EACCES) on File.delete

I am trying to delete some XML files after I have finished using them and one of them is giving me this error:
'delete': Permission denied - monthly-builds.xml (Errno::EACCES)
Ruby is claiming that the file is write protected but I set the permissions before I try to delete it.
This is what I am trying to do:
#collect the xml files from the current directory
filenames = Dir.glob("*.xml")
#do stuff to the XML files
finalXML = process_xml_files( filenames )
#clean up directory
filenames.each do |filename|
File.chmod(777, filename) # Full permissions
File.delete(filename)
end
Any ideas?
This:
File.chmod(777, filename)
doesn't do what you think it does. From the fine manual:
Changes permission bits on the named file(s) to the bit pattern represented by mode_int.
Emphasis mine. File modes are generally specified in octal as that nicely separates the bits into the three Unix permission groups (owner, group, other):
File.chmod(0777, filename)
So you're not actually setting the file to full access, you're setting the permission bits to 01411 which comes out like this:
-r----x--t
rather than the
-rwxrwxrwx
that you're expecting. Notice that your (decimal) 777 permission bitmap has removed write permission.
Also, deleting a file requires write access to the directory that the file is in (on Unixish systems at least) so check the permissions on the directory.
And finally, you might want to check the return value from File.chmod:
[...] Returns the number of files processed.
Just because you call doesn't mean that it will succeed.
You may not have access to run chmod. You must own the file to change its permissions.
The file may also be locked by nature of being open in another application. If you're viewing the file in, say, a text editor, you might not be able to delete it.
In my case it was because the file I had been trying to delete--kindle .sdr record--was directory, not file. I need to use this instead:
FileUtils.rm_rf(dirname)

RUBYLIB Environment Path

So currently I have included the following in my .bashrc file.
export RUBYLIB=/home/git/project/app/helpers
I am trying to run rspec with a spec that has
require 'output_helper'
This file is in the helpers directory. My question is that when I change the export line to:
export RUBYLIB=/home/git/project/
It no longer finds the helper file. I thought that ruby should search the entire path I supply, and not just the outermost directory supplied? Is this the correct way to think about it? And if not, how can I make it so RUBY will search through all subdirectories and their subdirectories, etc?
Thanks,
Robin
Similar to PATH, you need to explicitly name the directory under which to look for libraries. However, this will not include any child directories within, so you will need to list any child sub-directories as well, delimiting them with a colon.
For example:
export RUBYLIB=/home/git/project:/home/git/project/app/helpers
As buruzaemon mentions, Ruby does not search subdirectories, so you need to include all the directories you want in your search path. However, what you probably want to do is:
require 'app/helpers/output_helper'
This way you aren't depending on the RUBYLIB environment variable being set a certain way. When you're deploying code to production, or collaborating with others, these little dependencies can make for annoying debugging sessions.
Also as a side note, you can specify . as a search path, rather than using machine-specific absolute paths.

Resources