daishi5 Posted December 16, 2009 Share Posted December 16, 2009 I have a scheduled task that was deployed using AT, and I have a script that I want to use to check that the scheduled task is installed on the correct domain machines. My only problem is, I have no experience working with strings. The output from AT is always formatted the same, so I just need to match a text string of c:\reboot.exe and if that is present in the string, I want to capture the number at the start of the line. Status ID Day Time Command Line ------------------------------------------------------------------------------- 1 Each W 5:30 AM c:\reboot.exe 2 Each W 5:30 AM c:\reboot.exeSo, for this, I would want to output 1 and 2 to variables or an array (I assume I want an array) so that I can then feed them back into more commands. This is what I have so far for grabbing the AT output. It is very basic, and I split it into several strings of 1 line each, because I think it reduces my chance of grabbing the wrong ID number. #include <Constants.au3> AutoItSetOption("MustDeclareVars", 1) dim $foo dim $line dim $count dim $test ;retrieve the scheduled tasks from the target machine $foo = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) Processwaitclose($foo) $line = string(StdoutRead($foo)) ;check the output from the AT command msgbox(1,"test",$line) ;split the output into seperate lines, and then double check the number of lines after the split $test = stringsplit($line,@LF) msgbox(1,"testcount",$test[0]) ;display each line one by one, just one more check $count=0 while $count<$test[0] $count=$count+1 msgbox(1,"test lines",$test[$count]) WEnd ExitIf it is necessary, I can also post the full script code, if there is a better way to go about scanning a batch of computers in the domain. Link to comment Share on other sites More sharing options...
PsaltyDS Posted December 16, 2009 Share Posted December 16, 2009 StringRegExp(). Give it a shot. If you have trouble with the RegExp pattern (it's own learning curve), post back here for help from (the many) RegExp geeks around here! Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
daishi5 Posted December 16, 2009 Author Share Posted December 16, 2009 StringRegExp(). Give it a shot. If you have trouble with the RegExp pattern (it's own learning curve), post back here for help from (the many) RegExp geeks around here! That will help, I had really hit a wall because I have never worked with strings and did not even know how to start looking at this. I will read the help file and see if I can get what I need. Link to comment Share on other sites More sharing options...
PsaltyDS Posted December 16, 2009 Share Posted December 16, 2009 That will help, I had really hit a wall because I have never worked with strings and did not even know how to start looking at this. I will read the help file and see if I can get what I need.If you get stuck, post what you tried for more help. There's nothing RegExp Geeks like better than training up a new RegExp Geek! Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
daishi5 Posted December 16, 2009 Author Share Posted December 16, 2009 (edited) If you get stuck, post what you tried for more help. There's nothing RegExp Geeks like better than training up a new RegExp Geek! Didn't take me long. Matching string looks like this: Status ID Day Time Command Line ------------------------------------------------------------------------------- 1 Each W 5:30 AM c:\reboot.exe 2 Each W 5:30 AM c:\reboot.exe The expression is $task=stringregexp($line, '([0-9]{1,2})(?i: Each [A-Z]{1,2} [0-9]:[0-9]{1,2} [A-Z]{1,2} c:\\reboot.exe)', 1) After this, I do a series of message boxes, $task[0] returns 1 like I expect, but $task[1] gives me an "Array variable has incorrect number of subscripts or subscript dimension range exceeded" error. I tried the regular expression tester that I found in the help file, the test string works in there, but I assume I broke something in my array. Now for my new questions: Not sure what I am doing wrong, when I did this using stringsplit I did not have to declare the size of the array, should I be doing that here? Is there a way to output the number of matches stored in the array, or do I have to go through the array till I stop finding information stored in them when I use the output? Is there an easier way to ignore all the text between the first number and "c:\reboot.exe" I managed to make it work, but I bet I am missing a much easier method. Edit: Ok, I think I may have found why I am getting only the 1 back. Reading the help file, it seems that I am probably getting the "1" as an error rather than an actual match. This is a problem, because I actually expect to receive "1" back fairly often, so I need to figure out how to tell the difference between a "1" as an error and a "1" as a valid result. So, I will do some more help file digging. Edited December 16, 2009 by daishi5 Link to comment Share on other sites More sharing options...
PsaltyDS Posted December 16, 2009 Share Posted December 16, 2009 If you get an error, there won't be an array returned (good idea to test @error and/or IsArray()). And test with Ubound() before you assume a certain number of elements in any returned array. Your case insensitive marker needs to be all by itself: "(?i)" The rest that group is being ignored. So far, so good. Keep learning! Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
daishi5 Posted December 16, 2009 Author Share Posted December 16, 2009 If you get an error, there won't be an array returned (good idea to test @error and/or IsArray()). And test with Ubound() before you assume a certain number of elements in any returned array. Your case insensitive marker needs to be all by itself: "(?i)" The rest that group is being ignored. So far, so good. Keep learning! Ok, from the help section "(?i: ... ) Case-insensitive non-capturing group." I thought that meant that I could put the ?i: at the front of the group, and it would not match case and would not capture that group. Also, how do I test @error and isarray()? I found a few instances of @error in example code, but the help file does not say anything other than I should check seterror. I tried what I had seen which was if @error then but it went straight to the else portion of the code. However, I also tried If Isarray($task) Then which returns true, and executes the "Then" statement. I assume this means this is an array, but I don't know if I am testing @error properly, and I can't find how I should test it in the help files. Is there some reference I could read on basic validation such as testing @error and Isarray()? Oh, and thanks for the ubound suggestion, I have used that before and completely forgot. Link to comment Share on other sites More sharing options...
PsaltyDS Posted December 16, 2009 Share Posted December 16, 2009 Ok, from the help section "(?i: ... ) Case-insensitive non-capturing group." I thought that meant that I could put the ?i: at the front of the group, and it would not match case and would not capture that group.The group "(?i)" makes every group from there on case insensitive. The operative part of "(?i: ...)" is "non-capturing". "Capturing" here means matching it and adding it to the array. So you can pull some parts of the text but not others by having some groups be capturing, and others non-capturing. Also, how do I test @error and isarray()? I found a few instances of @error in example code, but the help file does not say anything other than I should check seterror. I tried what I had seen which was if @error then but it went straight to the else portion of the code. However, I also tried If Isarray($task) Then which returns true, and executes the "Then" statement. I assume this means this is an array, but I don't know if I am testing @error properly, and I can't find how I should test it in the help files. Is there some reference I could read on basic validation such as testing @error and Isarray()? Oh, and thanks for the ubound suggestion, I have used that before and completely forgot. Try this: #include <Array.au3> Global $aInput[2] = [" 1 Each W 5:30 AM c:\reboot.exe", _ " 2 Each W 5:30 AM c:\reboot.exe"] For $n = 0 To UBound($aInput) - 1 $task = StringRegExp($aInput[$n], '([0-9]{1,2})(?i)(\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)', 1) If @error = 0 And IsArray($task) And UBound($task) >= 2 Then ConsoleWrite("ID = " & $task[0] & "; Info = " & $task[1] & @LF) Else ConsoleWrite($n & ": Error" & @LF) EndIf Next Note the use of "\s+" instead of trying to include all the spaces between parts. Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
daishi5 Posted December 16, 2009 Author Share Posted December 16, 2009 The group "(?i)" makes every group from there on case insensitive. The operative part of "(?i: ...)" is "non-capturing". "Capturing" here means matching it and adding it to the array. So you can pull some parts of the text but not others by having some groups be capturing, and others non-capturing. Try this: #include <Array.au3> Global $aInput[2] = [" 1 Each W 5:30 AM c:\reboot.exe", _ " 2 Each W 5:30 AM c:\reboot.exe"] For $n = 0 To UBound($aInput) - 1 $task = StringRegExp($aInput[$n], '([0-9]{1,2})(?i)(\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)', 1) If @error = 0 And IsArray($task) And UBound($task) >= 2 Then ConsoleWrite("ID = " & $task[0] & "; Info = " & $task[1] & @LF) Else ConsoleWrite($n & ": Error" & @LF) EndIf Next Note the use of "\s+" instead of trying to include all the spaces between parts. Ok, that seems to have helped, it at least helped me figure out what was happening and what was not happening. Not an error, it just matches the first line, but not the second line. I took what you gave me and changed it to make the second part non-capturing, because I am just interested in that first number. However that helps because now I know my error checking was actually working, and the 1 is an actual match. When I tried your suggestion exactly as it was, I got a match on "1" and "Each W 5:30 AM c:\reboot.exe" but I did not get any matches on the second part, which I think should also match. So far my code looks like this: #include <Constants.au3> #include <Array.au3> AutoItSetOption("MustDeclareVars", 1) dim $cmdresult dim $line dim $count dim $test dim $task dim $arraylimit ;retrieve the scheduled tasks from the target machine $cmdresult = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) Processwaitclose($cmdresult) $line = string(StdoutRead($cmdresult)) ;check the output from the AT command msgbox(1,"test",$line) $task=stringregexp($line,'([0-9]{1,2})(?i)(?:\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)',1) if isarray($task) then Else msgbox(1,"error","No matches found") ;Exit EndIf if @error>0 Then msgbox(1,"array error","no matches, array is invalid") EndIf $arraylimit=ubound($task) msgbox(1,"array limit",$arraylimit) $count=0 while $count<$arraylimit msgbox(1,"regular expression output",$task[$count]) $count=$count+1 WEnd Exit I was running the Ifarray() and @error because I was not sure I was doing either right, so there is a lot of extra crap in there. As I look at your example and my code, and I see how your code outputs the matches from the regular expression, I think I have a few ideas of what I might be able to do to fix it. I am headed home for the day, but I think I will continue to play with this at home, it feels like I am making some simple mistake in my implementation, and that I am a simple fix away at this point. Link to comment Share on other sites More sharing options...
Mison Posted December 17, 2009 Share Posted December 17, 2009 Try non regex solution: $string = "1 Each W 5:30 AM c:\reboot.exe"&@CRLF&"2 Each W 5:30 AM c:\reboot.exe" $lines = StringSplit($string,@CRLF) $number = "" For $i = 1 To $lines[0] If StringInStr($lines[$i],"c:\reboot.exe") Then $number = $number & " - " & StringLeft($lines[$i],1) Next MsgBox(0,"",$number) Hi ;) Link to comment Share on other sites More sharing options...
PsaltyDS Posted December 17, 2009 Share Posted December 17, 2009 (edited) Try non regex solution: $string = "1 Each W 5:30 AM c:\reboot.exe"&@CRLF&"2 Each W 5:30 AM c:\reboot.exe" $lines = StringSplit($string,@CRLF) $number = "" For $i = 1 To $lines[0] If StringInStr($lines[$i],"c:\reboot.exe") Then $number = $number & " - " & StringLeft($lines[$i],1) Next MsgBox(0,"",$number)That nicely illustrates the inflexibility that can creep in when simplifying things. That fails on a two digit ID number, doesn't account for variable spaces in front of the ID in the original, and if the executable or it's path is different, etc. I'm not saying it can't be fixed to work with simple string manipulation, just that this topic is now an exercise in learning RegExps because they are much more powerful and flexible, making them easier to use when the task is more complex. Edited December 17, 2009 by PsaltyDS Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law Link to comment Share on other sites More sharing options...
daishi5 Posted December 17, 2009 Author Share Posted December 17, 2009 I found a fix, although I am not sure if I should have needed to do this. I placed the StringRegExp in a loop, and broke the output from the AT command into separate lines so that I could check them one at a time. I thought I could run the StringRegExp on the whole set of text, and output each of the matches, but this seemed to work. I am guessing the way I ran it, I was only getting the first match. For my own education, is there a way to return all of the matches, or is looping the best way? Thank you for all the help. I am sure Mison's code could work, but the answer was so close there was no point in switching methods. The finalized "test" code. $cmdresult = Run('at \\lteis007', "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) Processwaitclose($cmdresult) $line = string(StdoutRead($cmdresult)) ;check the output from the AT command msgbox(1,"test",$line) ;split the AT command results into individual lines to be parsed $test=stringsplit($line,@lf) ;check for errors in the string split, if everything seems to have worked, begin parsing the output if isarray($test) and @error=0 Then for $count=0 to ubound($test)-1 msgbox(1,"string value",$test[$count]) ;check each line for the targeted script $task=stringregexp($test[$count],'([0-9]{1,2})(?i)(?:\s+Each [A-Z]{1,2}\s+[0-9]{1,2}:[0-9]{1,2} [A-Z]{2}\s+c:\\reboot.exe)',1) if isarray($task) and @error=0 Then for $innercount=0 to ubound($task)-1 msgbox(1,"regexp output",$task[$innercount]) Next EndIf Next EndIf Link to comment Share on other sites More sharing options...
danielkza Posted December 18, 2009 Share Posted December 18, 2009 You can retrieve all matches of an regular expression by using flag 3 or 4 in StringRegExp. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now