Ruby symlink not working in OS X - ruby

The following script creates symlinks as expected, but the original file can never be found. Can someone tell me why? They appear to be valid symlinks because they register as aliases in OS X and File.symlink? returns true once they have been created.
#!/usr/bin/env ruby
case ARGV.first when 'link'
file = ARGV[1]
if !File.exist?(file)
puts "Unfortunately, \"#{file}\" was not found."
exit 0
end
bin = "/usr/local/bin/"
if !File.directory?(bin)
puts "#{bin} does not exist!"
puts "creating #{bin}..."
system "mkdir -p #{bin}"
end
if File.extname(file).empty?
if File.symlink?(bin + file)
puts "Unfortunately, \"#{bin + file}\" already exists."
exit 0
end
name = bin + file
puts "Symlinking #{file} to #{name}..."
File.symlink(file, name)
system "chmod +x #{name}"
else
name = file.split(File.extname(file))
name = bin + name.first
if File.symlink?(name)
puts "Unfortunately, \"#{name}\" already exists."
exit 0
end
puts "Symlinking #{file} to #{name}..."
File.symlink(file, name)
system "chmod +x #{name}"
end
else
puts "try: bin link <file>"
end
The script is run in the following way:
ruby script.rb link myfile.rb

To answer my own question, replacing the instances of
File.symlink(file, name)
with
File.symlink(File.expand_path(file), name)
worked perfectly.

Related

rename files with Ruby

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.)

Upload files from local directory to SFTP using Ruby

For some reason SFTP upload in Ruby (copy files from local directory to SFTP server) doesn't seem to work. I'm currently using Ruby 2.5.3. I would really appreciate any ideas :
My code below:
require 'net/ssh'
require 'net/sftp'
server = 'sftp.secure.net'
username = '123456'
password = "Mypassword*"
uid = '123456'
files = Dir.entries(outdir)
Net::SFTP.start(server, username, :password=>password) do |sftp|
for filename in files
#puts files
puts "Browsing files..."
puts "File: #{filename}"
#puts new_filename
####### replacing , for | ########
if /#{uid}_test_[0-9]{8}_[0-9]{8}.txt$/ =~ filename
file = "#{outdir}\\#{filename}"
puts "SFTPing #{file}"
sftp.upload(file)
puts "SFTP Complete for file #{file}"
puts "Cleanup"
puts "Deleting #{file}."
File.delete(file)
puts "Files were deleted."
end
end
puts "Closing SFTP connection..."
sftp.close
puts "SFTP connection closed."
end
Thank you Kennycoc! That upload! was definitely helpful. Also, sftp.close() should be deleted for sftp. The SFTP connection automatically close. This is needed for FTP I found out, but not for SFTP.
Thanks!
Finalized Version:
files = Dir.entries(outdir)
Net::SFTP.start(hostname, username, :password=>password) do |sftp|
for filename in files
#puts files
puts "Browsing files..."
puts "File: #{filename}"
#puts new_filename
####### replacing , for | ########
if /#{uid}_test_[0-9]{8}_[0-9]{8}.txt$/ =~ filename
file = "#{outdir}\\#{filename}"
puts "SFTPing #{file}"
sftp.upload!(file)
puts "SFTP Complete for file #{file}"
puts "Cleanup"
puts "Deleting #{file}."
File.delete(file)
puts "Files were deleted."
end
end
#puts "Closing SFTP connection..."
#sftp.close()
puts "SFTP connection closed."
end
SFTP is an entirely different protocol based on the network protocol SSH (Secure Shell).
Read SFTP vs. FTPS: The Key Differences
.
Use gem net-sftp.
Ex:
require "net/sftp"
Net::SFTP.start("host", "username", :password: "password") do |sftp|
#from your system(local)
sftp.upload!("/path/to/local", "/path/to/remote")
# through URL
open(your_file_url) do |file_data|
sftp.upload!(file_data, /path/to/remote)
end
end

Changing Directory by Ruby

I am trying to create a simple script to delete all the files from my Desktop(I am using Ubuntu).
puts "Started at #{Time.now}"
Dir.chdir("/Desktop")
Dir.entries(".").each do |file|
if file.to_s.include?("xlsx")
puts "Deleting file #{file}" unless file == "." || file == ".."
File.delete "#{Dir.pwd}/#{file}" unless file == "." || file == ".."
end
end
puts "Ended on #{Time.now}"
But when I generate the code it throws the below error:
chdir': No such file or directory # dir_chdir - /Desktop
(Errno::ENOENT)
What I am doing wrong?
puts "Started at #{Time.now}"
Dir.chdir("#{ENV['HOME']}/Desktop")
Dir.entries(".").select { |file| file.ends_with?('.xlsx') }.each do |file|
puts "Deleting file #{file}"
File.delete "#{Dir.pwd}/#{file}"
end
puts "Ended on #{Time.now}"

File.exist? always returns false even when file does exist

I have a program that tries to open a file:
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: ";
relPath = gets;
absPath = Dir.pwd << "/" << relPath;
if File.exist?(absPath) then
puts "File exists";
file = File.open(absPath, "r");
other code...
else
puts "File does not exist";
end
It always prints "File does not exist" even when the current directory exists and the file also exists. The file and script are in the same directory.
I am running it on Mac OS X Yosemite (10.10.3) and Ruby 2.2.0p0.
I can't explain why (albeit I have strong belief that it's for some whitespace characters) but with this little contribution it works ok.
Dir.chdir(File.dirname(__FILE__))
print "Enter file name:";
relPath = gets.chomp; #intuitively used this, and it wroked fine
absPath = File.expand_path(relPath) #used builtin function expand_path instead of string concatenation
puts absPath
puts File.file?(absPath)
if File.exist?(absPath) then
puts "File exists";
puts File.ctime(absPath) #attempting a dummy operation :)
else
puts "File does not exist";
end
runnning code
$ ls -a anal*
analyzer.rb
$ ruby -v
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
ziya#ziya:~/Desktop/code/ruby$ ruby fileexists.rb
Enter file name:analyzer.rb
/home/ziya/Desktop/code/ruby/analyzer.rb #as a result of puts absPath
true #File.file?(absPath) => true
File exists
2015-06-11 12:48:31 +0500
That code has syntax error ("if" doesnt need "then"), and you dont have to put ";" after each line.
try
Dir.chdir(File.dirname(__FILE__))
puts "Enter file name: "
relPath = gets
absPath = "#{Dir.pwd}/#{relPath.chop}"
if File.exist?(absPath)
puts "File exists"
file = File.open(absPath, "r")
else
puts "File does not exist"
end
remember that gets will add a new line character so you will need to do a chomp, and that way to concatenate string won't work on ruby.
Your code is not idiomatic Ruby. I'd write it something like this untested code:
Dir.chdir(File.dirname(__FILE__))
puts 'Enter file name: '
rel_path = gets.chomp
abs_path = File.absolute_path(rel_path)
if File.exist?(abs_path)
puts 'File exists'
File.foreach(abs_path) do |line|
# process the line
end
else
puts 'File does not exist'
end
While Ruby supports the use of ;, they're for use when we absolutely must provide multiple commands on one line. The ONLY time I can think of needing that is when using Ruby to execute single-line commands at the command-line. In normal scripts I've never needed ; between statements.
then is used with if when we're using a single line if expression, however, we have trailing if which removes the need for then. For instance, these accomplish the same thing but the second is idiomatic, shorter, less verbose and easier to read:
if true then a = 1 end
a = 1 if true
See "What is the difference between "if" statements with "then" at the end?" for more information.
Instead of relPath and absPath we use snake_case for variables, so use rel_path and abs_path. It_is_a_readability AndMaintenanceThing.
File.absolute_path(rel_path) is a good way to take the starting directory and return the absolute path given a relative directory.
File.foreach is a very fast way to read a file, faster than slurping it using something like File.read. It is also scalable whereas File.read is not.

How to change rvm gemset over ssh on os x server

ok
I don't know how to change rvm version over ssh under os x server.
What I do:
Login on server over ssh
run script (below) and catch error
Error: 'rvm is not a funciton, many-many-words'
What I have as script:
use File::Spec;
my $server_directory = File::Spec->catfile($ENV{HOME},'MyProject');
my $exec_file = File::Spec->catfile($server_directory,'run_script.rb');
my $run_ruby_script = qq'bundle exec ruby $exec_file'.' '.join(' ',#ARGV);
# reload bash profile
print qx(source $ENV{HOME}/.bash_profile);
print qx(source $ENV{HOME}/.bashrc);
# reload ruby
print qx(source $ENV{HOME}/.rvm/scripts/rvm);
my $ruby_setup = qq([[ -s "$ENV{HOME}/.rvm/scripts/rvm" ]] && source "$ENV{HOME}/.rvm/scripts/rvm");
print $ruby_setup. "\n";
# change directory
chdir($server_directory);
# configure gemset name
my $version = qx(cat .ruby-version);
chomp($version);
my $gemset = qx(cat .ruby-gemset);
chomp($gemset);
my $change_rvm_gemset = qq(rvm use $version\#$gemset);
print qx($ruby_setup && $change_rvm_gemset);
print qx(rvm current);
Ok, after all.
def exec_via_bash(line)
puts %Q(#{line})
exec = 'bash -c "#{line}"'
puts `#{exec}`
end
def RubySetup
# reload bash profile
homedir = ENV['HOME']
exec_via_bash %Q(source #{homedir}/.bash_profile);
exec_via_bash %Q(source #{homedir}/.bashrc);
# reload ruby
exec_via_bash %Q(source #{homedir}/.rvm/scripts/rvm);
ruby_setup = %Q([[ -s "#{homedir}/.rvm/scripts/rvm" ]] && source "#{homedir}/.rvm/scripts/rvm")
puts ruby_setup
ruby_setup
end
if ARGV.empty?
puts "there is not enough arguments passed. maybe you forget ruby file to exec?"
exit(1)
end
ruby_script_path = ARGV.shift;
exec_file_absolute_path = File.expand_path(ruby_script_path)
unless File.exists? exec_file_absolute_path
puts "file #{exec_file_absolute_path} doesn't exists!"
exit(1)
end
exec_file_directory = File.dirname(exec_file_absolute_path)
exec_bundle = %Q'bundle exec ruby #{exec_file_absolute_path}' + ' ' + ARGV.join(' ')
# change directory
Dir.chdir(exec_file_directory);
# print %x(ls);
# configure gemset name
version = %x(cat .ruby-version).strip;
gemset = %x(cat .ruby-gemset).strip;
change_rvm_gemset = %Q(rvm use #{version}\##{gemset});
ruby_setup = RubySetup()
exec_bash_login_line = [ruby_setup, change_rvm_gemset, exec_bundle].join ' && ';
puts 'exec bash login line: ' + exec_bash_login_line
forced = %Q(bash --login -c '#{exec_bash_login_line}');
puts forced, "\n";
puts %x(#{forced});
ok, this script is not a kind of beauty, but it works well.
Example of usage?
ruby script.rb ~/bla/bla/bla/run_your_program.rb --first_argument --second_argument a,b,c --etc
As I said before:
I've already on the server via ssh.
So, I need to run scripts via launchd.
And I should do it with
# part of launchd worker
<string>bash</string>
<string>-c</string>
<string>ruby ~/PathToCharmScript.rb -r a</string>
P.S:
Please, help me with improvements of this script for others!
Here is a gist: wow_this_works

Resources