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.
Related
Wondering if anyone here can help with this problem. I have custom profiles for certain games that I wish to run but having problems.
In this example, I have a mega drive profile, and a mortal kombat profile.
Below is my runcommand-onstart.sh file. I got some of the code from someone else I found here I think, but have made changes as it didn’t work for me. The script outputs to a log for test purposes. The text output to the log is correct, but doesn’t do what it should, see below:
#!/usr/bin/env bash
# Get system name
system=$1
emulator=$2
rom=$3
command=$4
# rom_bn receives $rom excluding everything from the first char to the last slash '/'
rom_bn="${rom##*/}"
# rom_bn receives $rom_bn excluding everything from the last char to the first dot '.'
rom_bn="${rom_bn%.*}"
rom_joined='"'$rom_bn'"'
# Write to Runcommand Log to test
echo emitter LoadProfileByEmulator "$rom_joined" $1 >> $HOME/start.log
emitter LoadProfileByEmulator "$rom_joined" $1
The command I wish to run is:
emitter LoadProfileByEmulator "Mortal Kombat (World)" megadrive
The test log has the following line:
emitter LoadProfileByEmulator "Mortal Kombat (World)" megadrive
But ledspicer loads the megadrive profile… like it can't read the "Mortal Kombat" bit.
If I copy and paste that line from the log into terminal, ledspicer loads the Mortal Kombat profile as it should….
Many thanks for any help
Quotes aren't processed in the expansion of variables, so when you add quotes to $rom_joined, those are being treated literally. But since the profile doesn't actually have quotes in its name, that doesn't work.
Just quoting the variable in the argument to emitter is enough to make it a single word. If you want the quotes in the log, do that in the echo command.
#!/usr/bin/env bash
# Get system name
system=$1
emulator=$2
rom=$3
command=$4
# rom_bn receives $rom excluding everything from the first char to the last slash '/'
rom_bn="${rom##*/}"
# rom_bn receives $rom_bn excluding everything from the last char to the first dot '.'
rom_bn="${rom_bn%.*}"
# Write to Runcommand Log to test
echo "emitter LoadProfileByEmulator '$rom_joined' '$system'" >> $HOME/start.log
emitter LoadProfileByEmulator "$rom_bn" "$system"
I have a script that contains 2 variables. One of the variables is a directory path and the other is a user input variable. Once the user enters the variable, in this case a certificate name, I use sed to replace the text of xxxxx with both the script_path separated by a / and the the certfile variable.
Still new at programming but I've managed to get my script working aside from the issue below. I've tried escaping the variables the "/" and nothing seems to work.
I've also tried changing the delimiter that sed uses as well with no luck. I did search around quite a bit and didn't find anything specific with using a "/" and concatenating variables so apologies up front if this has already been solved.
#!/bin/bash
script_path=/opt/ceflog
read -p 'Enter the name of the certificate file: ' certfile
sed -e "s/pkcs12_file = xxxxxx/pkcs12_file = $script_path/$certfile/g" \$script_path/cef.conf
What is should look like is something like the below.
pkcs12_file = /opt/ceflog/192.168.1.1_1.pkcs12
As always thanks in advance for you help.
I guess you want to do something like this
$ path='/opt/ceflog'; cert='192.168.1.1_1.pkcs12';
$ echo pkcs12_file = xxxxxx/pkcs12_file |
sed -E 's~(pkcs12_file =) (xxxxxx/pkcs12_file)~\1 '"${path}/${cert}"'~'
pkcs12_file = /opt/ceflog/192.168.1.1_1.pkcs12
use a different sed delimiter (here I picked ~) than the default one (/), since you may have it in your data.
So looks like there were 2 issues. I escaped the use of the variables on the end "\$script_path/cef.conf" and changing the dilemeter for sed I was able to get it to work.
sed -e "s|pkcs12_file = xxxxxx|pkcs12_file = $script_path/$certfile|g" $script_path/cef.conf
Thanks again all.
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..
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
I have an ascii file and in there somewhere is the line:
BEGIN
and later on the line:
END
I'd like to be able to remove those two lines and everything in between from a command line call in windows. This needs to be completely automated.
EDIT: See sed in Vista - how to delete all symbols between? for details on how to use sed to do this (cygwin has sed).
EDIT: I am finding that SED could be working but when I pipe the output to a file, the carriage returns have been removed. How can I keep these? Using this sed regex:
/^GlobalSection(TeamFoundationVersionControl) = preSolution$/,/^EndGlobalSection$/{
/^GlobalSection(TeamFoundationVersionControl) = preSolution$/!{
/^EndGlobalSection$/!d
}
}
.. where the start section is 'GlobalSection(TeamFoundationVersionControl) = preSolution' and the end section is 'EndGlobalSection'. I'd also like to delete these lines as well.
EDIT: I am now using something simpler for sed:
/^GlobalSection(TeamFoundationVersionControl) = preSolution$/,/^EndGlobalSection$/d
The line feeds are still an issue though
Alternately, what I use these days is a scripting language that plays nicely with windows like Ruby or Python for such tasks. Ruby is easy to install in windows and makes problems like this child's play.
Here's a script you could use like:
cutBeginEnd.rb myFileName.txt
sourcefile = File.open(ARGV[0])
# Get the string and do a multiline replace
fileString = sourceFile.read()
slicedString = fileString.gsub(/BEGIN.*END\n/m,"")
#Overwrite the file
sourcefile.pos = 0
sourcefile.print slicedString
sourcefile.truncate(f.pos)
This does a pretty good job, allows for a lot of flexiblity, and is possibly more readable than sed.
Here is a 1-line Perl command that does what you want (just type it from the Command Prompt window):
perl -i.bak -ne "print unless /^BEGIN\r?\n/ .. /^END\r?\n/" myfile.txt
Carriage returns and line feeds will be preserved properly. The original version of myfile.txt will be saved as myfile.txt.bak.
If you don't have Perl installed, get ActivePerl.
Here's how to delete the entire GlobalSection(TeamFoundationVersionControl) = preSolution section using a C# regular expression:
// Create a regex to match against an entire GlobalSection(TeamFoundationVersionControl) section so that it can be removed (including preceding and trailing whitespace).
// The symbols *, +, and ? are greedy by default and will match everything until the LAST occurrence of EndGlobalSection, so we must use their non-greedy counterparts, *?, +?, and ??.
// Example of string to match against: " GlobalSection(TeamFoundationVersionControl) ...... EndGlobalSection "
Regex _regex = new Regex(#"(?i:\s*?GlobalSection\(TeamFoundationVersionControl\)(?:.|\n)*?EndGlobalSection\s*?)", RegexOptions.Compiled);