How to pass ruby variable into sed command in Shell? - ruby

This is my code. I want to grab the p's value and insert it into the file changed.txt when matched 1. But it doesn't do what I want to, it seems it doesn't know what #{p} is
Net::SSH.start( "192.168.2.1", "root", :password => "password") do |ssh|
p = ssh.exec! "java -cp /var/lib/sonar/dev-tools.jar au.com.Tool test"
# puts #{p}
ssh.exec! "sed 's/1/#{p}/g' changed.txt"
end

The passing of the p value the way you have it should work fine. However, the sed command doesn't change the file. If you want it to change the file in place, use the -i option like so:
ssh.exec! "sed -i 's/1/#{p}/g' changed.txt"
Or if you want the changes in a different file, then use:
ssh.exec! "sed 's/1/#{p}/g' changed.txt > newfile.txt"
An alternative option would be:
ssh.exec! "sed -i 's/1/" + p + "/g' changed.txt"

Related

How to print the output on the console?

I am trying to show the "curl's" output on the console when I execute it. Below is what I wrote. It prints the statement that I declared in puts for all the hostnames, which is as per designed.
desc "check_app_version <environment> <project>", "checks the /dev/info page of the app"
def check_app_version(environment, project)
check_environment(environment)
machines = `knife node list`.split
machines.each do |hostname|
puts "checking the app-version for #{hostname}"
system("curl --silent -m 5 #{hostname}:8080/dev/info |grep 'Application\|Build'")
end
end
But I don't see anything for the next line which instructs to perform a curl on my servers.
Use the backtick notation to return a string, then return to puts
puts `curl --silent -m 5 #{hostname}:8080/dev/info |grep 'Application\|Build'`
puts `curl --silent -m 5 #{hostname}:8080/dev/info |grep 'Application\\|Build'`

How can I get the output of an ssh command?

I'd like to programmatically check if someone has their SSH keys set up correctly for GitHub. I understand that I can use `ssh -T git#github.com` in Ruby. However, I'd like to keep the ssh output in a variable.
My current code is:
github_response = `ssh -T git#github.com`
unless github_response.start_with?('Hi')
puts 'Please set up your GitHub ssh keys'
end
`ssh -T git#github.com` outputs the response (starting with "Hi"). However the github_response variable is nil.
How can I assign the output of `ssh -T git#github.com` to github_response?
Your example failed because the Hi xxx! You've successfully authenticated.... message is not from stdout, but stderr.
> require 'open3'
=> true
> stdin, stdout, stderr, wait_thr = Open3.popen3('ssh -T git#github.com')
=> [#<IO:fd 8>, #<IO:fd 9>, #<IO:fd 11>, #<Thread:0x007f89ee1149a8 sleep>]
> stdout.gets
=> nil
> stderr.gets
=> "Hi halfelf! You've successfully authenticated, but GitHub does not provide shell access.\n"
You could add -v for verbose output, it will then dump much of the connection info to stdout. From that log you can scrape to find whether the server accepted any of the keys the ssh client offered

Escaping an ampersand character ('&') in a password for a Ruby script

I have a password like 'X&Y' and I am trying to run a Ruby script that opens an SSH session, but the script breaks at the & character like :
*server: X
*server: bash: Y: command not found
Escaping the character like & doesn't help either. Ideas appreciated!
The code where it happens is at the ssh.exec:
pass="X\&Y"
Net::SSH.start( host_name, user, :password => pass ) do |ssh|
#do stuff
command = "sudo -S rm file"
cmd = "#{pass}|#{command}"
ssh.exec(cmd) do |ch, stream, data|
puts "*server:" + data.inspect
end
end
You can use ssh like without & getting any special meaning:
ssh -t -t user#localhost "echo 'abc&def'"
abc&def
Connection to localhost closed.

How can I use \w in double quoted string in Ruby

I'm using Capistrano for deployment and I need to run a command for setting the correct environment in the .htaccess file on the server.
I do that with sed like this: run "sed -i -r 's/APPLICATION_ENV \w+/APPLICATION_ENV #{stage}/' #{current_release}/public/.htaccess"
My problem is that the \w+ is escaped by Ruby/Cap and the regexp ends up trying to match only w+. If I use \\w+ I end up with a regexp that attempts to match \\w+.
How can I have an interpolated double quoted string and successfully escape the \w? Do I really need to change to concatenation of single quoted string and variables?
On my sysem your sample works but you could try it with one of these two (comment the ones out you don't use)
begin
stage = "stage"
current_release = "current_release"
s = "sed -i -r 's/APPLICATION_ENV \\w+/APPLICATION_ENV #{stage}/' #{current_release}/public/.htaccess"
s = "sed -i -r 's/APPLICATION_ENV #{"\\w+"}/APPLICATION_ENV #{stage}/' #{current_release}/public/.htaccess"
s = "sed -i -r 's/APPLICATION_ENV #{92.chr}w+/APPLICATION_ENV #{stage}/' #{current_release}/public/.htaccess"
puts s
system s
rescue
puts $!
system('pause')
end

How to gsub slash "/" with back slash and slash "\/" in ruby

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.

Resources