How to make system( ... ) return a stream of strings as output after running Ruby script? - ruby

I am writing a ruby script where I am making use of the command
system('git log')
along with some flags and formatting preferences to show me the time, revision id and file name of each file that was added in a repo.
How can I make the result of this command (i.e which is the information stated above for each file) to be a single string, one for each file added in repo and then put all these strings inside an array?
Example of current result:
2016-10-11T22:07:06+01:00 b3d0893: example.txt
2016-10-11T22:06:06+01:00 b3d0893: example1.txt
I want the above to be two different strings and then put them in an array.

Kernel#system just returns true or false depending on the success of the call. STDOUT from the call is simply output, so you can't really do anything with it, as you've found out.
If you switch to using backticks instead you should get a String returned with STDOUT from the command:
output = `git log`
To split that output string into an Array of lines, use String#split, so you get something like
output = `git log`
lines = output.split(/\n/)

Related

Dynamically generating the filename for svn status output

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

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.

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

Ruby returning null when printing same string again

I am modifying a pre-receive hook of gitlab
the code which returns branch name is
print ARGF.read
print "\n"
refs = ARGF.read
print refs
first time when i do print or puts i get the branch name but again second time whenever i use the same string it returns nothing. nil or empty string.
Any clue why is this happening. I am new to ruby, so unable to figure out.
ARGF is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.
The manual states that ARGF::read
Reads _length_ bytes from ARGF. The files named on the command line
are concatenated and treated as a single file by this method, so when
called without arguments the contents of this pseudo file are returned in
their entirety.
You might want to use ARGF::readline
Returns the next line from the current file in ARGF.
or maybe ARGF::rewind
Positions the current file to the beginning of input, resetting ARGF.lineno to zero.
A call ARGF.read is not idempotent, that is you cannot invoke it many times and expect the same result as it will "consume" all the command line arguments passed to your hook.
If you want to reuse the command line arguments you have to first store them in a local variable and then do what you want with them
refs = ARGF.read
print refs
print "\n"
# do something here with your arguments
print "\n"

How do I open / manipulate multiple files in bash?

I have a bash script that take advantage of a local toolbox to perform an operation
my question is fairly simple
I have multiple files that are the same quantities but different time steps i would like to first untar them all, and then use the toolbox to perform some manipulation but i am not sure if i am on the right track.
=============================================
The file is as follows
INPUTS
fname = a very large number or files with same name but numbering
e.g wnd20121.grb
wnd20122.grb
.......
wnd2012100.grb
COMMANDS
> cdo -f nc copy fname ofile(s)
(If this is the ofile(s)=output file how can i store it for sequent use ? Take the ofile (output file) from the command and use it / save it as input to the next, producing a new subsequent numbered output set of ofile(s)2)
>cdo merge ofile(s) ofile2
(then automatically take the ofile(s)2 and input them to the next command and so on, producing always an array of new output files with specific set name I set but different numbering for distinguishing them)
>cdo sellon ofile(s)2 ofile(s)3
------------------------------------
To make my question clearer, I would like to know the way in which I can instruct basically through a bash script the terminal to "grab" multiple files that are usually the same name but have a different numbering to make the separate their recorded time
e.g. file1 file2 ...file n
and then get multiple outputs , with every output corresponding to the number of the file it converted.
e.g. output1 output2 ...outputn
How can I set these parameters so the moment they are generated they are stored for subsequent use in the script, in later commands?
Your question isn't clear, but perhaps the following will help; it demonstrates how to use arrays as argument lists and how to parse command output into an array, line by line:
#!/usr/bin/env bash
# Create the array of input files using pathname expansion.
inFiles=(wnd*.grb)
# Pass the input-files array to another command and read its output
# - line by line - into a new array, `outFiles`.
# The example command here simply prepends 'out' to each element of the
# input-files array and outputs each (modified) element on its own line.
# Note: The assumption is that the filenames have no embedded newlines
# (which is usually true).
IFS=$'\n' read -r -d '' -a outFiles < \
<(printf "%s\n" "${inFiles[#]}" | sed s'/^/out-/')
# Note: If you use bash 4, you could use `readarray -t outFiles < <(...)` instead.
# Output the resulting array.
# This also demonstrates how to use an array as an argument list
# to pass to _any_ command.
printf "%s\n" "${outFiles[#]}"

Resources