Maybe I have been coding for too many hours, but I can't realize why I am having a hard time escaping simple-quotation-marks in this Ruby string:
s = "echo '%name%' > /etc/hostname"
puts s
# => "echo '%name%' > /etc/hostname"
s.gsub!(/'/, "\\'")
puts s
# => "echo %name%' > /etc/hostname%name% > /etc/hostname > /etc/hostname"
exit(0)
When doing s.gsub!(/'/, "\\'") I am expecting to get "echo \'%name%\' > /etc/hostname", but instead I am getting "echo %name%' > /etc/hostname%name% > /etc/hostname > /etc/hostname"
Related
I have a list of scripts doing their own thing (they are actually Rscripts reading modifying and writing files) like this:
## Script 1
echo "1" > file1.out
## Script 2
echo "2" > file2.out
## Script 3
echo "3" > file3.out
These are saved in different scripts as follow:
## Writing script 1
echo "echo \"1\" > file1.out" > script1.task
## Writing script 2
echo "echo \"2\" > file2.out" > script2.task
## Writing script 3
echo "echo \"3\" > file3.out" > script3.task
Is there a way to run all these scripts in parallel using the file names?
In a loop it'd look like this:
for task_file in *.task
do
sh ${task_file}
done
If you only have 3 the answer is to use &.
But if you have 1000s:
seq 10000 | parallel 'echo {} > file{}.out'
Following advice from Andre Wildberg and user1934428 here's a solution using & just for the record:
for task_file in *.task
do
sh ${task_file} &
done
wait
I am launching a nohup remote script with Ruby Net/SSH.
Net::SSH.start(ip_address, user, options) do |ssh|
script = File.join(remote_path, 'run_case.py')
cmd = "nohup python #{script} #{args} < /dev/null &"
ssh.exec(cmd)
end
All stdout and stderr is saved to a file on the remote machine.
Is it possible to get the PID of the remote script so that I can kill it if needed?
EDIT 1:
I have modified the script as suggested.
Net::SSH.start(ip_address, user, options) do |ssh|
script = File.join(remote_path, 'run_case.py')
cmd = "nohup python #{script} #{args} < /dev/null & echo $! > save_pid.txt"
ssh.exec(cmd)
pid = ssh.exec!("cat save_pid.txt")
puts mesh_pid
end
It complains that it cannot find the file. Is this because the file does not exist yet? I would prefer to avoid any sleep command if possible
EDIT 2: Maybe this is not elegant but it works. I have created a second ssh session and used pgrep.
Net::SSH.start(ip_address, user, options) do |ssh|
script = File.join(remote_path, 'run_case.py')
cmd = "nohup python #{script} #{args} < /dev/null &"
ssh.exec(cmd)
end
Net::SSH.start(ip_address, user, options) do |ssh|
cmd = "python #{script} #{args}"
mesh_pid = ssh.exec!("pgrep -f '#{cmd}'")
puts mesh_pid
end
You should be able to determine the PID (and store it in a file) as follows:
Net::SSH.start(ip_address, user, options) do |ssh|
script = File.join(remote_path, 'run_case.py')
cmd = "nohup python #{script} #{args} < /dev/null & echo $! > save_pid.txt"
ssh.exec(cmd)
end
In a script, $! represents the PID of the last process executed. If you need to kill the process, you can do it via:
kill -9 `cat save_pid.txt`
rm save_pid.txt
Neovim's job-control example in :help job-control works well for bash scripts. However, I am unable to make it work for ruby. Consider the following example:
set nocp
set buftype=nowrite
call jobstart('shell', 'bash', ['-c', 'for ((i = 0; i < 5; i++)); do sleep 2 && printf "Hello Bash!\n"; done'])
call jobstart('shell', 'ruby', ['-e', '5.times do sleep 2 and puts "Hello Ruby!" end'])
function JobHandler()
if v:job_data[1] == 'exit'
let str = v:job_data[0] . ' exited'
else
let str = join(v:job_data[2])
endif
call append(line('$'), str)
endfunction
au JobActivity shell* call JobHandler()
Running nvim -u NONE -S <filename> produces the following output:
Hello Bash!
Hello Bash!
Hello Bash!
Hello Bash!
Hello Bash!
1 exited
Hello Ruby! Hello Ruby! Hello Ruby! Hello Ruby! Hello Ruby!
2 exited
How do we make the ruby example work like that for bash?
It turns out that ruby's output is being buffered. One has to force it to be flushed in order to see the desired output.
call jobstart('shell', 'ruby', ['-e', '$stdout.sync = true; 5.times do sleep 1 and puts "Hello Ruby!\n" end'])
My original problem was to run a ruby test asynchronously. For it to work, I had to write $stdout.sync = true to a file and require it using -r:
call jobstart('shell', 'ruby', ['-r', '/tmp/opts.rb', '-I', 'test', 'test/unit/user_test.rb'])
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
I try to modify "/foo/bar/dir" to "\/foo\/bar\/dir" by ruby gsub command.
I test it in irb the result is
x = "/foo/bar/dir"
x.gsub("/","\/")
=> "/foo/bar/dir"
x.gsub("/","\\/")
=> "\\/foo\\/bar\\/dir"
Is it possible to replace "/" with "/" by gsub ?
Source of problems:
I try to execute "string in command line" and "real_path" is my variable
real_path = "/home/me/www/idata"
path = real_path.gsub("/","\\/")
=> \\/home\\/me\\/www\\/idata
# But what I expect is \/home\/me\/www\/idata
run "sed 's/SHARE_PATH/#{path}/g' #{path}/config/sphinx.yml > #{path}/config/sphinx.tmp.yml"
result from "run" command is
"sh -c 'sed '\''s/SHARE_PATH/\\/home\\/me\\/www\\/idata\\/shared/g .... "
I need is only one back slash like
"sh -c 'sed '\''s/SHARE_PATH/\/home\/me\/www\/idata\/shared/g .... "
"run" is command from Capistrano
my solution is
use single quote instead of double quote like this
path = real_path.gsub("/",'\/')
You have written:
x = "/foo/bar/dir"
x.gsub("/","\\/")
=> "\\/foo\\/bar\\/dir"
so You did what You had asked before. x.gsub("/","\\/") in fact evaluates to "\/foo\/bar\/dir" but irb prints return value of inspect method instead of to_s.
Edit: Did You mean
real_path.gsub("/","\/")
istead of
real_path.gsub("\/","\/")
Anyway the output is correct - You changed / with \/ so You have
"sh -c 'sed '\''s/SHARE_PATH/\/home\/me\/www\/idata\/shared/g'\'' .... "`
instead of
`"sh -c 'sed '\''s/SHARE_PATH//home/me/www/idata/shared/g'\'' .... "`
and result is different from irb's result (notice the lack of doubled backslash).
For path manipulation I recommend using File.join (documentation)
By the way: why are You modifying the path this way? (1)
Edit2: Why are You asking about changing "/" to "/" but write the following line?
path = real_path.gsub("\/","\\/")
What are You trying to achieve? And what is Your answer to question (1) ?
Edit3:
Here We go:
>> real_path = "/foo/bar/dir"
=> "/foo/bar/dir"
>> path = real_path.gsub("/", "\\/")
=> "\\/foo\\/bar\\/dir"
>> puts "sed 's/SHARE_PATH/#{path}/g' #{path}/config/sphinx.yml > #{path}/config/sphinx.tmp.yml"
sed 's/SHARE_PATH/\/foo\/bar\/dir/g' \/foo\/bar\/dir/config/sphinx.yml > \/foo\/bar\/dir/config/sphinx.tmp.yml
=> nil
>>
but I do not understand why You need backslash in a path?
Yes
irb(main):028:0> (t = x.gsub("/", "\\/")) && nil
=> nil
irb(main):029:0> t
=> "\\/foo\\/bar\\/dir"
irb(main):030:0> puts t
\/foo\/bar\/dir
=> nil
Your first example actually did what you wanted, but the .inspect method that irb is using is escaping backslashes, so it looked like there were extras. If you had used puts you would have seen the real result.