I just have a question about writing a function that will search a directory for the most recent log in a directory. I currently came up with one, but I'm wondering if there is a better (perhaps more proper) way of doing this.
I'm currently using hdsentinel to create logs on computer and placing the log in a directory. The logs are saved like so:
/directory/hdsentinel-computername-date
ie. C:/hdsentinel-owner-2010-11-11.txt
So I wrote a quick script that loops through certain variables to check for the most recent (within the past week) but after looking at it, I'm question how efficient and proper it is to do things this way.
Here is the script:
String directoryPath = "D:"
def computerName = InetAddress.getLocalHost().hostName
def dateToday = new Date()
def dateToString = String.format('%tm-%<td-%<tY', dateToday)
def fileExtension = ".txt"
def theFile
for(int i = 0; i < 7; i++) {
dateToString = String.format('%tY-%<tm-%<td', dateToday.minus(i))
fileName = "$directoryPath\\hdsentinel-$computerName-$dateToString$fileExtension"
theFile = new File(fileName)
if(theFile.exists()) {
println fileName
break;
} else {
println "Couldn't find the file: " + fileName
}
}
theFile.eachLine { print it }
The script works fine, perhaps it has some flaws. I felt I should go ahead and ask what the typical route is for this type of thing before I continue with it.
All input is appreciated.
Though a bit messy, you could implement a multi-column sort via the 'groupBy' method (Expounding on Aaron's code)..
def today = new Date()
def recent = {file -> today - new Date(file.lastModified()) < 7}
new File('/yourDirectory/').listFiles().toList()
.findAll(recent)
.groupBy{it.name.split('-')[1]}
.collect{owner, logs -> logs.sort{a,b -> a.lastModified() <=> b.lastModified()} }
.flatten()
.each{ println "${new Date(it.lastModified())} ${it.name}" }
This finds all logs created within the last week, groups them by owner name, and then sorts according to date modified.
If you have files other than logs in the directory, you may first need to grep for files containing 'hdsentinel.'
I hope this helps.
EDIT:
From the example you provided, I cannot determine if the least significant digit in the format:
C:/hdsentinel-owner-2010-11-11.txt
represents the month or the day. If the latter, sorting by file name would automatically prioritize by owner, and then by date created (without all of the chicanery of the above code).
For Instance:
new File('/directory').listFiles().toList().findAll(recent).sort{it.name}
Hopefully this helps some..This sorts a given path by date modified in a groovier way. The lists them out.
you can limit the list, and add other conditions in the closure to get the desired results
new File('/').listFiles().sort() {
a,b -> a.lastModified().compareTo b.lastModified()
}.each {
println it.lastModified() + " " + it.name
}
As I was trying to solve a similar problem, learnt a much cleaner approach.
Define a closure for sorting
def fileSortCondition = { it.lastModified() }
And File.listFiles() has other variation which accepts FileFilter and FilenameFilter in Java, and these interfaces has a single method called accept, Implement the interface as a closure.
def fileNameFilter = { dir, filename ->
if(filename.matches(regrx))
return true
else
return false
} as FilenameFilter
And lastly
new File("C:\\Log_Dir").listFiles(fileNameFilter).sort(fileSortCondition).reverse()
Implement FileFilter interface if filtering is to be done by File attributes.
def fileFilter = { file ->
if(file.isDirectory())
return false
else
return true } as FileFilter
Related
trying to return string builder in a loop. is this workable.. I am collecting a list with each(), then appending 'it' to "scriptBldr_" to create a different object name each time to hold the string. then I collect the object names in a list. And trying to return using a for loop for each object name. But it's failing.
List.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
StringBuilder $builderstring = StringBuilder.newInstance()
if (ValidUDA == "Region") {
$builderstring <<"""
XYZCode
"""
StringBuilders.add(builderstring)
}
}
for(item in StringBuilders)
{
return item
}
I guess the following code does what you intended to code:
def myList = ['Hello "World"', 'asb"r"sd']
def ValidUDA = "Region"
def builders = [:]
myList.each {
String builderstring = "scriptBldr_" + it.replaceAll (/"/, '')
builders[builderstring] = StringBuilder.newInstance()
if (ValidUDA == "Region") {
builders[builderstring] <<"""
XYZCode
"""
}
}
return builders
A return statement will immediatly return from the method and hence will exit the loop and only called once. So, I guess, what you wanted to achieve is to return a list of StrinngBuilders.
some hints:
it is unusual in Groovy to start a variable with $ and you can run into problems with such a naming
when asking a question on SO, try to come up with a working example. As you can see, you example was missing some definitions
Update: as you've stated in you comment that you tryed to create dynamic variable names, I've updated the code to use maps. The returned map now contains the StringBuilders together with their names.
The problem is:
I have a method
def comparison_reporter(list_of_scenarios_results1, list_of_scenarios_results2)
actual_failed_tests = list_of_scenarios_results2.select {|k,v| v == 'Failed'}
actual_passed_tests = list_of_scenarios_results2.select {|k,v| v == 'Passed'}
failed_tests = Array.new(actual_failed_tests.length) { Hash.new }
failed_tests.each do |hash|
actual_failed_tests.keys.map {|name| hash["test_name"] = name}
actual_failed_tests.values.map {|new_status| hash["actual_status"] = new_status}
list_of_scenarios_results1.values_at(*actual_failed_tests.keys).map {|old_status| hash["previous_status"] = old_status}
end
final_result = {
"passed_tests_count" => list_of_scenarios_results2.select {|k,v| v == 'Passed'}.length,
"failed_tests_count" => list_of_scenarios_results2.select {|k,v| v == 'Failed'}.length,
"failed_tests" => failed_tests
}
return final_result
end
This method takes 2 hashes as arguments and returns the result of their comparison and some other things. Currently, it always returns failed_tests with two (or more) identical hashes (same key-value pairs).
I think, that problem is somewhere in failed_tests.each do |hash| block, but I can't find the reason of this bug, please advice. Example of the method result (in .json format)
{
"passed_tests_count": 3,
"failed_tests_count": 2,
"failed_tests": [
{
"test_name": "As a user I want to use Recent searches tab",
"actual_status": "Failed",
"previous_status": "Failed"
},
{
"test_name": "As a user I want to use Recent searches tab",
"actual_status": "Failed",
"previous_status": "Failed"
}
]
}
UPD:
hash1 (first argument) -
{""=>"Passed",
"As a new user I want to use no fee rentals tab"=>"Passed",
"As a new user I want to use Luxury rentals tab"=>"Passed",
"As a user I want to use Recent searches tab"=>"Failed",
"As a user I want to use new listings for you tab"=>"Passed"}
hash2 (second argument)-
{""=>"Passed",
"As a new user I want to use no fee rentals tab"=>"Failed",
"As a new user I want to use Luxury rentals tab"=>"Passed",
"As a user I want to use Recent searches tab"=>"Failed",
"As a user I want to use new listings for you tab"=>"Passed"}
Example of desired desired output:
{
"passed":"count",
"failed":"count",
"failed_tests": [
{"test_name":"As a user I want to use Recent searches tab",
"actual_status":"failed",
"previous_status":"failed"},
{"test_name":"As a new user I want to use no fee rentals tab",
"actual_status":"failed",
"previous_status":"passed"}]
}
Solution:
def comparison_reporter(before, after)
failed_tests = after.select { |k,v| v == "Failed" }.map do |k,v|
{
test_name: k,
actual_status: v,
previous_status: before[k]
}
end
{
passed: after.size - failed_tests.size,
failed: failed_tests.size,
failed_tests: failed_tests
}
end
Simplified failed_tests quite a bit. Since we calculate number of failed tests, we can use it for the final counts, instead of iterating over the hash again.
The problem is on line 8: You're overwriting hash["previous_status"] with the last value in list_of_scenarios_results1.values_at(*actual_failed_tests.keys) when you map over it.
Usually you use map to assign an iterable to something, not modify something else.
e.g.
x = ['1','2','3'].map(&:to_i)
rather than
x = []; ['1','2','3'].map {|v| x << v.to_i}
I'd suggest re-thinking your approach. Will you always have the same keys in both hashes? If so you could simplify this. I'd also suggest looking into byebug. It's an interactive debugger that'll let you step through your function and see where things aren't doing what you expect.
I'm really fresh to Python and need help reading information from txt file. I have a large C++ app need to duplicate it in Python. Sadly I have no idea where to start. I've been reading and watching some tutorials, but little help from them and I'm running out of time.
So my task is:
I have a shopping list with:
-Name of the item, price and age.
I also need to create two searches.
Search whether the item is in the shop (comparing strings).
if name of the item is == to the input name.
Search by age. Once the program finds the items, then it needs to print the list according to the price - from the lowest price to the highest.
For example you input age 15 - 30, the program prints out appropriate
items and sorts them by the price.
Any help would be nice. At least from where I could start.
Thank you.
EDITED
So far, I have this code:
class data:
price = 0
agefrom = 0
ageto = 0
name = ''
# File reading
def reading():
with open('toys.txt') as fd:
toyslist = []
lines = fd.readlines()
for line in lines:
information = line.split()
print(information)
"""information2 = {
'price': int(information[1])
'ageftom': int(information[2])
'ageto': int(information[3])
#'name': information[4]
}"""
information2 = data()
information2.price = int(information[0])
information2.agefrom = int(information[1])
information2.ageto = int(information[2])
information2.name = information[3]
toyslist.append(information2)
return toyslist
information = reading()
I HAVE A PROBLEM WITH THIS PART. I want to compare the user's input with the item information in the txt file.
n_search = raw_input(" Please enter the toy you're looking for: ")
def name_search(information):
for data in information:
if data.name == n_search:
print ("We have this toy.")
else:
print ("Sorry, but we don't have this toy.")
If you want to fins something in a list it's generally as straightforward as:
if "apple" in ["tuna", "pencil", "apple"]
However, in your case, the list to search is a list of lists so you need to "project" it somehow. List comprehension is often the easiest to reason about, a sort of for loop in a for loop.
if "apple" in [name for name,price,age in [["tuna",230.0,3],["apple",0.50,1],["pencil",1.50,2]]]
From here you want to start looking at filters whereby you provide a function that determines whether an entry is matched or not. you can roll your own in a for loop or use something more functional like 'itertools'.
Sorting on a list is also easy, just use 'sorted(my_list)' supplying a comparator function if you need it.
Examples as per your comment...
class ShoppingListItem:
def __init__(self,name,price,age):
self.name=name
self.price=price
self.age=age
or
from collections import namedtuple
sli = namedtuple("ShoppingListItem",['name','age','price'])
I have the gradle task that should create Websphere profile on Windows OS
task createProfile(type:Exec) {
def commandToExecute = new StringBuffer()
def profile = 'AppSrv02'
def wasHome = 'C:/IBM new/WebSphere/AppServer'
def str = new LinkedList <String> ();
str.add('cmd')
str.add('/c')
str.add(wasHome + '/bin/manageprofiles.bat')
str.add('-create')
str.add('-profileName')
str.add(profile)
//str.add('-templatePath')
//str.add(wasHome + '/profileTemplates/default')
println (str)
commandLine str.toArray()
}
And the problem appears if I uncomment commented lines, after it task fails and say me that: "C:/IBM" is not valid batch file. If I put profileTemplates not in the folder that contains spaces, everything works fine again. But templates should lies int wasHome( And sometimes wasHome has spaces(
I have, now ideas why adding templates key with value with spaces influence in such way that Gradle tries to start "C:/IBM" instead specified 'C:/IBM new/WebSphere/AppServer/bin/manageprofiles.bat'. It seems that, possibly, problem inside java.lang.ProcessBuilder.
I tries to quote paths, by adding "/"" but nothing works(((( what isn't surprise, because ProcessBuilder implies quoting by itself if it is needed.
So, I am asking if anybody had the similar problem and could recommend how to work around this issue? Thanks in advance.
If somebody needed it, we found a workaround for this problem. The task finally looks like:
task createProfile(type: Exec) {
executable = new File(wsadminLocation, manageProfilesFileName)
def templatePath = wasHome + File.separator + "profileTemplates" + File.separator + "default"
def argsList = ["-create", "-profileName", profile, "-templatePath", templatePath, "-nodeName", nodeName, "-cellName", wasCellName, "-enableAdminSecurity", isProfileSecured, "-adminUserName", rootProject.wasLogin, "-adminPassword", rootProject.wasPassword]
args = argsList
}
The basic idea is to pass the arguments to the Gradle not as long string, but as a list. So in this way there aren't any problems if an argument contains a space.
Change following lines
def wasHome = '"C:/IBM new/WebSphere/AppServer'
...
str.add(wasHome + '/bin/manageprofiles.bat"')
That way, the full path to the batch file is quoted.
EDITED - As stated by dbenhan, a little obfuscated. This "should" be something like
task createProfile(type:Exec) {
def commandToExecute = new StringBuffer()
def profile = 'AppSrv02'
def wasHome = 'C:/IBM new/WebSphere/AppServer'
def str = new LinkedList <String> ();
str.add('cmd')
str.add('/c')
str.add('"' + wasHome + '/bin/manageprofiles.bat"')
str.add('-create')
str.add('-profileName')
str.add(profile)
str.add('-templatePath')
str.add('"' + wasHome + '/profileTemplates/default"')
println (str)
commandLine str.toArray()
}
BUT, while gradle in particular and windows in general can handle paths with slash separators, i have no idea if manageprofiles.bat can, and you are passing a parameter with a path in it. Maybe, you will need to change your paths to 'c:\\IBM new\\....'
Try This
task xyz {
def result1 = exec {
workingDir "D:/abc/efg"
commandLine 'cmd', '/c', 'CDUTIL.bat', "qwe", "rty"
}
println result1.toString()
}
While trying to make a simple register/signup client only application for a personal project. I'm trying to load a list of users from a file, and compare them to a possible username. If the username already exists, the program will give them an error.
Here is a condensed clone of the code:
u1 = str(input("Input username: "))
t = open("userlistfile","r")
userlist = t.readline()
y = 0
for x in range(0, len(userlist)-1):
if userlist[y] == u1:
print("\n !Error: That username (",u1,") is already taken!")
y += 1
The user list is stored in a file so that it can opened, appended, and saved again, without being stored in the program. My current issue is that the userlist is saved as a string rather than an array. Is there a better way to do this? Thank you.
EDIT: Thanks to user lorenzo for a solution. My Friends are telling me to post a quick (really simple) copy of a for you guys who can't figure it out.
New code:
u1 = str(input("Input username: "))
t = open("userlistfile","r")
userlist = t.read() #Readline() changed to Read()
userlist = userlist.split('--') #This line is added
y = 0
for x in range(0, len(userlist)-1):
if userlist[y] == u1:
print("\n !Error: That username (",u1,") is already taken!")
y += 1
Example text file contents:
smith123--user1234--stacky
This line will seperate the string at the ('--') seperators and append each split part into an array:
userlist = userlist.split('--')
#Is used so that this (in the text file)
Smith123--user1234--stacky
#Becomes (in the program)
userlist = ['Smith123','user1234','stacky']
Sorry for the long post... Found it very interesting. Thanks again to Lorenzo :D.
userlist = t.readline()
reads one line from the file as a string. Iterating, then, gets characters in the string rather than words.
You should be able to get a list of strings (words) from a string with the split() method of strings or the more general re.split() function.