Dynamically generating the filename for svn status output - ruby

I have a chef-infra set-up with chef-node as a windows server. The cookbook (recipe) is trying to take the status of the svn working copy folder and write it in a file. The nomenclature of the output file is CHEFRPT_TESTREPO_ddmmyyyy hh:mm:ss.txt. However, the following code is failing to generate the desired
filename with date and time dynamically.
Following is the ruby code of the recipe:
time = Time.now
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command 'svn status > D:\SVN_CHECKOUT\REPORTS\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H:%M:%S")}.txt'
end
Need some help regarding the variable to be appended at the end of the file to generate the filename with current date and time when it was generated.
Thank You!

You have to use double quotes " instead of your single quotes ' if you want to to interpolate code within a string with #{...}.
As you use single quotes in the command argument, this interpolation will not be performed and the string will be used as is (that is, including the #{time.stftime...} code in the string.
Your final resource should thus look like this:
time = Time.now
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command "svn status > D:\\SVN_CHECKOUT\\REPORTS\\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H:%M:%S")}.txt"
end
See https://ruby-doc.org/core/doc/syntax/literals_rdoc.html#label-Strings for details about String literal syntax in Ruby.

This issue is coming up because file/folder names in Windows cannot have the colon (:) character. Try manually creating a file though UI or command line. Also see naming a file for the list of special characters that render the filename invalid.
Since we are creating a timestamp with time.strftime("%Y-%m-%d%H:%M:%S"), execute block is failing. Changing %H:%M:%S to some other accepted character should be enough.
Also, as #Holger Just pointed out in his answer, we need to use double quotes to interpolate the value of time.strftime.
In the example below I've used hyphen (-), i.e. %H-%M-%S:
execute 'stat' do
cwd 'D:\inetpub\TEST_APP'
command "svn status > D:\SVN_CHECKOUT\REPORTS\CHEFRPT_TESTREPO_#{time.strftime("%Y-%m-%d%H-%M-%S")}.txt"
end

Related

change file extension with a ruby script

I'm trying to change the exstension of a file passing the arguments by console
system = "rename" , "'s/\#{ARGV[0]}$/\#{ARGV[1]}'", "*#{ARGV[1]}"
The code is correct because it works on console but when I put it in a script I have trouble with
s/\#
because it appears in pink and the console does not get it.
you don't want to send literal single quotes, so remove them.
you want to remove the backslashes so you let Ruby evaluate those expressions.
you're missing the trailing slash.
what's that equal sign doing?
did you want ARGV[0] in the last argument to rename, instead of ARGV[1]?
you want to use * wildcard, which requires a shell to expand into a list of files, which means you can't use the list form of system
Try
system "/usr/bin/rename -n 's/#{ARGV[0]}$/#{ARGV[1]}/' *#{ARGV[0]}"
Remove the -n option if it looks like you're going to rename the way you want.
And, of course, you don't need to call out to the shell for this:
Dir.glob("*#{ARGV[0]}").each {|fname|
newname = fname.sub(/#{ARGV[0]}$/, ARGV[1])
File.rename(fname, newname)
}

How to output file name inside system(git log) command in ruby script?

The problem I encounter is that I don't manage to put the name of the file inside the below screen output inside git log using pretty format flag.
An extract of my code is the following:
filename = File.basename file
system('git log --pretty=format:"%cd: (here I want the filename)"')
presented as sample.c for example.
I tried #{filename} but is interpreted as a string from the compiler and the result is the same as the input.
Thank you in advance.
It is interpreting it as a string because single quotes do now allow string interpolation.
system('git log --pretty=format:"%cd: (here I want the filename)"')
You can change this to use double quotes so you can take advantage of interpolation and escaping.
system("git log --pretty=format:\"%cd: #{filename}\"")
https://ruby-doc.org/core-2.1.1/doc/syntax/literals_rdoc.html

rrdtool xport filename with spaces

I'm trying to call rrdtool xport command on arbitrary number of files, so I'm writing a script that reads in the rrd file names and builds the DEF argument. The problem is some of the rrd files have whitespaces in them, i.e. "foo bar.rrd" (-_-)...and when the DEF argument is generated, it looks something like this:
DEF:a=foo bar.rrd:sum:AVERAGE
and when this is passed in to the rrdtool command, it generates an error saying "problems reading database name". I also have tried inserting the escape character ("\") before whitespace so it would look like "foo\ bar.rrd", but when this is run in bash, it still produces same error, whereas when I echo the command and copy paste it on the prompt and run it then it works fine...
Just put quotes around the whole thing
"DEF:a=foo bar.rrd:sum:AVERAGE"
rrdtool should be fine with the spaces.

Bash variable character replacement ends up to an empty string or a command not valid

I am working on a shell script to retrieve variable content from a JSON file via JQ. The JSON file is in string format (no matter whether this is a real string or a number) and to retrieve the variable in my bash script I did something like this
my_domain=$(cat /vagrant/data_bags/config.json | jq ."app"[0]."domain")
The above code once echoed results in "mydomain" with a beginning and a trailing quote sign. I though this was a normal behaviour of the echo command. However, while concatenating my variable with another shell command the system raise an error. For instance, the following command
cp /vagrant/public_html/index.php "/var/www/"+$my_domain+"/index.php"
fails with the following error
cp: cannot create regular file `/var/www/+"mydomain"+/index.php': No such file or directory
At this stage, I wasn't able to identify whether it's me doing the wrong concatenation with the plus sign or the variable is effectively including the quotes that in any case will end up generating an error.
I have tried to replace the quotes in my variable, but I ended up getting the system raising a "Command not found" error.
Can somebody suggest what am I doing wrong?
+ is not used for string concatenation in bash (or perl, or php). Just:
cp /vagrant/public_html/index.php "/var/www/$my_domain/index.php"
Embedding a variable inside a double-quoted text string is known as interpolation, and is one of the reasons why we need the $ prefix, to indicate that this is a variable. Interpolation is specifically not done inside single quoted strings.
Braces ${my_domain} are not required because the / directory separators are not valid characters in a variable name, so there is no ambiguity.
For example:
var='thing'
echo "Give me your ${var}s" # Correct, appends an 's' after 'thing'
echo "Give me your $vars" # incorrect, looks for a variable called vars.
If a variable (like 'vars') does not exist then (by default) it will not complain, it will just give an empty string. Braces (graph brackets) are required more in c-shell (csh or tcsh) because of additional syntax for modifying variables, which involves special trailing characters.
You don't need to use + to concatenate string in bash, change your command to
cp /vagrant/public_html/index.php "/var/www/"${my_domain}"/index.php"
My problem was not related only to the wrong concatenation, but also to the JQ library that after parsing the value from the JSon file was returning text between quotes.
In order to avoid JQ doing this, just add the -rawoutput parameter when calling JQ.

How can I run a unix command without using a space character so that I can execute a remote command?

I've been learning about remote/arbitrary command execution. In doing so, I came across some Ruby I thought would be fun to try and exploit.
I've been somewhat successful as I managed to get it to run the 'ls' command, but I can't work out how to add space characters into my commands. If I add a space in, the parse method that URI calls throws an exception.
Here's the code I was trying to exploit:
injection = "www.google.com';ls;#"
require 'uri'
URI.parse(injection)
puts `curl '#{injection}'`
So your challenge, should you choose to accept it, is to run an 'ls -l' command instead of 'ls' by only changing the injection string. You may not change anything but the first line.
Things I've tried:
ls%2f-l - # Doesn't raise an exception but unix doesn't unescape CGI encodings.
ls\x20-l - # Raises an exception because Ruby parses the UTF-8.
# Other various escape combinations (\\x20, etc)
Maybe it's not possible?
Thanks
You can use the Internal Field Separator (<space><tab><newline>). Since this is what the shell separates with anyway, it will accept it as a separator.
injection = "www.google.com';ls$IFS-l;#"
(BTW, thanks for a nice Saturday night puzzle.)
Is - it's possible. Just put your string in quotes:
1) from a command prompt:
two strings # No quote: the shell sees two strings
"one string" # with single (') or double quotes (") the shell sees only one string
2) from a string literal
mystring = "\"this will be interpreted as one string\"";

Resources