Trying to create a Ruby script. I want to append Strings containing commands to a file - ruby

mysqldump = "mysqldump"
`#{mysqldump} > backup_file.sql`
I'm supposed to append several of those mysqldump Strings (I simplified it for this example; normally line 2 would have the username and password as options) into the SQL file.
The problem is line 2, when I try to call the Bash operator '>' to append the String. Instead of appending, the script ends up calling the mysqldump command itself.
What can I do to store the String "mysqldump" into the file backup_file.sql? I want to do it the same way as line 2: automatically appending through the Bash.

if you are trying to append "like" you said and not overwrite the target file use >> instead of > . Here is a working version of your script:
za$ emacs ./foo.rb
#!/usr/bin/env ruby
target_dir = "/Users/za/ruby-practice/backup_file.sql"
mysqldump = "mysqldump"
`echo #{mysqldump} >> "#{target_dir}"`
You can also do something like : system %Q{echo "#{mysqldump}" >> "#{target_dir}"}
. Personally , I would say use IO#puts instead of making system calls inside your script , if you want a pure ruby solution/system independent solution.

Why don't you use pure ruby to do it? Like:
File.open("backup_file.sql", "w") do |f|
dump_lines.each do |line|
f.puts line
end
end
assuming that you have the dump in an array..

Related

How to make my script use a CSV file that was given in the terminal as a parameter

I tried to google this, but cant really find "good words" to get to my solution. So maybe someone here can help me out.
I have a script (lets call it script.rb) that uses File.read to read a csv file called somefile.csv and i have another csv file called somefileV2.csv.
Script.rb
csv_text = File.read('/home/XXX/XXX/XXX/somefile.csv')
Right now it uses somefile.csv as default, but I would like to know, if it is posseble to make my script use a CSV file that was given in the terminal as a parameter like:
Terminal
home$ script.rb somefileV2
so instead of it reading the file that is in the script, it reads the other csv file (somefileV2.csv) that is in the directory. It is kinda annoying to change the file manually everytime in the script itself.
You can access the parameters (arguments) using the ARGV array.
So your program could be like:
default = "/home/XXX/XXX/XXX/somefile.csv"
csv_text = File.read(ARGV[0] || default)
which gives you the possibility to supply a filename or, if not supplied, use the default value.
ARGV[0] refers to the first, ARGV[1] to the second argument and so on.
ruby myscript.rb foo bar baz would result in ARGV being
´["foo", "bar", "baz"]´. Note that the elements will always be strings. So if you want anything else (Numbers, Date, ...) you need to process it accordingly in your program.

Run bash script

I have this bash script which does something with a given input and passes it to a ruby script:
QUERY=$(iconv -f UTF8-MAC <<<'{query}')
/usr/bin/ruby start.rb $QUERY
This works fine so far.
I want to run the first line of this script inside a Ruby script, which passes the input to another Ruby script. I'm trying to do this using back-ticks in Ruby but it doesn't work the way I want as the query isn't converted. What am I doing wrong here?
input = `$(iconv -f UTF8-MAC <<<'{query}')`
Start.go(input)
I think you want to interpolate query, and string interpolation is allowed in backticks (in addition to double-quoted strings). The syntax for ruby string interpolation is #{string_to_interpolate}.
For example--if you put the following in an .rb. file and run it on a Windows system--then mspaint will launch:
var = 'mspaint.exe'
`#{var}`
It looks like you're just missing a # character on this line:
input = `$(iconv -f UTF8-MAC <<<'#{query}')`

How to bring system grep results into ruby

I'm currently grep-ing the system and returning the results into ruby to manipulate.
def grep_system(search_str, dir, filename)
cmd_str ="grep -R '#{search_str}' #{dir} > #{filename}"
system(cmd_str)
lines_array = File.open(filename, "r").read.split("\n)
end
As you can see, I'm just writing the results from the grep into a temp file, and then re-opening that file with "File.open".
Is there a better way to do this?
Never ever do anything like this:
cmd_str ="grep -R '#{search_str}' #{dir}"
Don't even think about it. Sooner or later search_str or dir will contain something that the shell will interpret in unexpected ways. There's no need to invoke a shell at all, you can use Open3.capture3 thusly:
lines = Open3.capture3('grep', '-R', search_str, dir).first
lines, _ = Open3.capture3('grep', '-R', search_str, dir)
That will leave you with a newline delimited list in lines and from there it should be easy.
That will invoke grep directly without using a shell at all. capture3 also nicely lets you ignore (or capture) the command's stderr rather than leaving it be printed wherever your stderr goes by default.
If you use this form of capture3, you don't have to worry about shell metacharacters or quoting or unsanitary inputs.
Similarly for system, if you want to use system with arguments you'd use the multi-argument version:
system('ls', some_var)
instead of the potentially dangerous:
system("ls #{some_var}")
You shouldn't need to pass an argument for the temporal filename. After all, writing and reading to/from a temporal file is something you should avoid if possible.
require "open3"
def grep_system(search_str, dir)
Open3.capture2("grep -R '#{search_str}' #{dir}").first.each_line.to_a
end
Instead of using system(cmd_str), you could use:
results = `#{cmd_str}`
Yes, there are a few better ways. The easiest is just to assign the result of invoking the command with backticks to a variable:
def grep_system(search_str, dir, filename)
cmd_str ="grep -R '#{search_str}' #{dir}"
results = `#{cmd_str}`
lines_array =results.split("\n)
end

Sed Issues in Ruby

I'm trying to update a site generator at work. One of the things that must be done is editing the gitosis.conf file to add the repo to the right group. This is how that block is currently set up in my gitosis.conf file.
[group sites]
writable = site1 site2 site3 randomsite awesomeness
members = #devs
So after countless tries, I've made a few "advancements" and then some steps back.
sed -i"" -e"/sites/,\$s/writable.*/& PROJECTNAME/" gitosis.conf
I was finally able to get the code to work on the CentOS command line, but now if I try to run it in irb (running it in a ruby script with backticks, so this has to work) I get this error:
sed: -e expression #1, char 22: unknown command: `&'
=> ""
"char 22" may be incorrect because I've edited some of the words a little bit to make the example more vanilla.
This is what is actually in the ruby script.
gitosis = `sed -i"" -e"/sites/,\$s/writable.*/& PROJECTNAME/" gitosis.conf`
I've been searching everywhere to try to fix this, but so far I've come up with nothing. I've read various places that a better option is ruby -pe in order to keep it ruby, but I don't even know where to start with that. Any advice/input would be awesome. Thank you!
Well you don't really need to escape the $ variable. Try using this -
gitosis = sed -i"" -e "/70/,/$/s/75/& #{p}/" gitosis.conf
OR
gitosis = sed -i"" -e "/70/,$ s/75/& #{p}/" gitosis.conf
Though I am not too sure what are you planning to do with the variable that you are assigning this sed one-liner to. Since it is an in-line substitution, you will get a variable with nothing in it.
Well you can do it with sed, if you can't do it other way, you can always go without & like:
gitosis = `sed -i"" -e"/plexus/,\$s/\(writable.*\)/\1 #{projectname}/" gitosis.conf`
But with ruby you can parse and write .ini files and your ruby script will work without sed!
This is untested code, written on the fly, but should get you started toward using a pure-Ruby solution:
# [group sites]
# writable = site1 site2 site3 randomsite awesomeness
# members = #devs
FILENAME = 'gitosis.conf'
# bail if the group is missing from the command line
abort('Missing group to add') if (ARGV.empty?)
# read the file
contents = File.read(FILENAME)
# find and extract the "writable" line
writable = contents[/^writable.+$/]
# open the new file. This will automagically close it when done.
File.open("#{FILENAME}.new", 'w') do |fo|
# output the current file, replacing the current writable line with one containing the old
# contents with the added new group followed by a line-ending.
fo.print contents.sub(writable, writable + ' ' + ARGV.shift + "\n")
end
# add code here to handle moving/deleting/something with the old file and
# moving the new file into place.

is it possible to concat arguments to a command line using backquotes ?

I would like to execute an OS command from my ruby script but I want to add an argument from a ruby variable.
I know that's possible by using keyword system like that :
#!/usr/bin/env ruby
directory = '/home/paulgreg/'
system 'ls ' + directory
but is that possible by using the "backquotes or backticks syntax" ?
(I mean by using that syntax : ls)
No, that will just concatenate the output from ls and the contents of directory.
But you can do this:
#!/usr/bin/env ruby
directory = '/home/paulgreg/'
`ls #{directory}`
`ls #{directory}`
isn't very safe because you're going to run into problems with path names that have spaces in them.
It's safer to do something like this:
directory = '/home/paulgreg/'
args = []
args << "/bin/ls"
args << directory
system(*args)
Nick is right, but there is no need to assemble the args piecewise:
directory = '/Volumes/Omg a space/'
system('/bin/ls', directory)

Resources