Cisco IOS routers, doing a "dir", and I want to grab all file names with ".bin" in the name.
Example string:
Directory of flash0:/
1 -rw- 95890300 May 24 2015 11:27:22 +00:00 c2900-universalk9-mz.SPA.153-3.M5.bin
2 -rw- 68569216 Feb 8 2019 20:15:26 +00:00 c3900e-universalk9-mz.SPA.151-4.M10.bin
3 -rw- 46880 Oct 25 2017 19:08:56 +00:00 pdcamadeusrtra-cfg
4 -rw- 600 Feb 1 2019 19:36:44 +00:00 vlan.dat
260153344 bytes total (95637504 bytes free)
I've figured out how to pull "bin", but I can't figure out how to pull the whole filename (starting with " c", ending in "bin"), because I want to then use the values and delete unwanted files.
I'm new to programming, so the regex examples are a little confusing.
You can use this regex
^[\w\W]+?(?=(c.*\.bin))\1$
^ - Start of string.
[\w\W]+? - Match anything one or more time ( Lazy mode ).
(?=(c.*\.bin)) - Positive lookahead match c followed by anything followed by \.bin ( Group 1)
\1 - Match group 1.
$ - End of string.
Demo
To match the filename that start with a c (or at the start of the string) you might use a negative lookbehind (?<!\S) to check what is on the left is not a non-whitespace character.
Then match either 1+ times not a whitespace character \S+ or list in a character class [\w.-]+ what the allowed characters are to match. After that match a dot \. followed by bin.
At the end you might use a word boundary \b to prevent bin being part of a larger word:
(?<!\S)[\w.-]+\.bin\b
regex101 demo
Thank you Code Maniac!
Your code finds one instance, and I needed to find all. Using what you gave me plus messing around with some other examples, I found this to work:
binfiles="{{ dir_response.stdout[0] | regex_findall('\b(?=(c.*.bin))\b') }}"
Now I get this:
TASK [set_fact] ********************************************************************************************************
task path: /export/home/e130885/playbooks/ios-switch-upgrade/ios_clean_flash.yml:16
Tuesday 12 February 2019 08:29:58 -0600 (0:00:00.350) 0:00:03.028 ******
ok: [10.35.91.200] => changed=false
ansible_facts:
binfiles:
- c2900-universalk9-mz.SPA.153-3.M5.bin
- c3900e-universalk9-mz.SPA.151-4.M10.bin
- c2800nm-adventerprisek9-mz.151-4.M12a.bin
Onto the next task of figuring out how to use each element. Thank you!
Related
I need to find all the records which contains the given sub-string(art), and the condition is the given substring is either a complete word within the string or the start of any word within the string.
Sample data. Program
id | name
-----------
10 | Report of Quarter 1
11 | The Art Program
12 | The Artificial Program
From the above data, I must be able to get the record numbers 11 and 12 but not 10.
I am trying like this
Program.where("name ~* ?",'art\b')
but it's not working
I have also tried with
Program.where("regexp_match(name, ?)",'/art\b/i')
this too is not working
any help is really appreciable. Thanks!
EDITED
I guess you are using Postgres since you gave an example with regexp_match
Try Program.where("name ~* ?",'\mart') :)
You can see hidden in the Postgres docs ("Regular Expression Escapes" section) that \b means "backspace, as in C" whereas \m "matches only at the beginning of a word"
I would like to check whether a year was found within a string. Something like
if string.scan(/\d{4}/).first == TRUE
for example a string looks like "there were 3 earthquakes in 2007"
Any suggestions?
If you want to match standalone 4 digit string, you may consider a regex with word boundaries:
!('It is 2016 now.' =~ /\b\d{4}\b/).nil? # => true
or - a more real world sample usage:
if string =~ /\b\d{4}\b/
The \b\d{4}\b matches any 4 digits that are not preceded nor followed with word characters (digits, letters or underscore), so there will be no match in 02312345.
Also, in case you want to precise to current century, or the 20th century, you may use /\b(?:19|20)\d{2}\b/ regex.
To extract the digits, use s[/\b\d{4}\b/].
'It was in 2015/16.'[/\b\d{4}\b/] # => 2015
See the Ruby demo
In VSTS (or TFS 2015) does the $(DayOfYear) build variable output with preceding zeros when under 100?
For example, would it output 063 or 63? Similarly, 003 or 3?
The reason I ask is because we use the following build number format:
$(Major).$(Minor).$(Year:yy)$(DayOfYear)$(Rev:.rr)
Technically, without preceeding zeros, 1.0.16179.01 (a build from 27th June 2016) would be considered as a later build than 1.0.173.01 (a build on 3rd Jan 2017). With preceding zeros, this version number would be correctly represented as 1.0.17003.01.
$(DayOfYear) always output a number with XXX format. So you will get "003" or "063" with zero filled.
I would like to do this using idiomatic Perl 6.
I found a wonderful contiguous chunk of data buried in a noisy output file.
I would like to simply print out the header line starting with Cluster Unique and all of the lines following it, up to, but not including, the first occurrence of an empty line. Here's what the file looks like:
</path/to/projects/projectname/ParameterSweep/1000.1.7.dir> was used as the working directory.
....
Cluster Unique Sequences Reads RPM
1 31 3539 3539
2 25 2797 2797
3 17 1679 1679
4 21 1636 1636
5 14 1568 1568
6 13 1548 1548
7 7 1439 1439
Input file: "../../filename.count.fa"
...
Here's what I want parsed out:
Cluster Unique Sequences Reads RPM
1 31 3539 3539
2 25 2797 2797
3 17 1679 1679
4 21 1636 1636
5 14 1568 1568
6 13 1548 1548
7 7 1439 1439
One-liner version
.say if /Cluster \s+ Unique/ ff^ /^\s*$/ for lines;
In English
Print every line from the input file starting with the once containing the phrase Cluster Unique and ending just before the next empty line.
Same code with comments
.say # print the default variable $_
if # do the previous action (.say) "if" the following term is true
/Cluster \s+ Unique/ # Match $_ if it contains "Cluster Unique"
ff^ # Flip-flop operator: true until preceding term becomes true
# false once the term after it becomes true
/^\s*$/ # Match $_ if it contains an empty line
for # Create a loop placing each element of the following list into $_
lines # Create a list of all of the lines in the file
; # End of statement
Expanded version
for lines() {
.say if (
$_ ~~ /Cluster \s+ Unique/ ff^ $_ ~~ /^\s*$/
)
}
lines() is like <> in perl5. Each line from each file listed on the command line is read in one at a time. Since this is in a for loop, each line is placed in the default variable $_.
say is like print except that it also appends a newline. When written with a starting ., it acts directly on the default variable $_.
$_ is the default variable, which in this case contains one line from the file.
~~ is the match operator that is comparing $_ with a regular expression.
// Create a regular expression between the two forward slashes
\s+ matches one or more spaces
ff is the flip-flop operator. It is false as long as the expression to its left is false. It becomes true when the expression to its left is evaluated as true. It becomes false when the expression to its right becomes true and is never evaluated as true again. In this case, if we used ^ff^ instead of ff^, then the header would not be included in the output.
When ^ comes before (or after) ff, it modifies ff so that it is also false the iteration that the expression to its left (or right) becomes true.
/^\*$/ matches an empty line
^ matches the beginning of a string
\s* matches zero or more spaces
$ matches the end of a string
By the way, the flip-flop operator in Perl 5 is .. when it is in a scalar context (it's the range operator in list context). But its features are not quite as rich as in Perl 6, of course.
I would like to do this using idiomatic Perl 6.
In Perl, the idiomatic way to locate a chunk in a file is to read the file in paragraph mode, then stop reading the file when you find the chunk you are interested in. If you are reading a 10GB file, and the chunk is found at the top of the file, it's inefficient to continue reading the rest of the file--much less perform an if test on every line in the file.
In Perl 6, you can read a paragraph at a time like this:
my $fname = 'data.txt';
my $infile = open(
$fname,
nl => "\n\n", #Set what perl considers the end of a line.
); #Removed die() per Brad Gilbert's comment.
for $infile.lines() -> $para {
if $para ~~ /^ 'Cluster Unique'/ {
say $para.chomp;
last; #Quit reading the file.
}
}
$infile.close;
# ^ Match start of string.
# 'Cluster Unique' By default, whitespace is insignificant in a perl6 regex. Quotes are one way to make whitespace significant.
However, in perl6 rakudo/moarVM the open() function does not read the nl argument correctly, so you currently can't set paragraph mode.
Also, there are certain idioms that are considered by some to be bad practice, like:
Postfix if statements, e.g. say 'hello' if $y == 0.
Relying on the implicit $_ variable in your code, e.g. .say
So, depending on what side of the fence you live on, that would be considered a bad practice in Perl.
I never wrote any complex regular expression before, and what I need seems to be (at least) a bit complicated.
I need a Regex to find matches for the following:
"On Fri, Jan 16, 2015 at 4:39 PM"
Where On will always be there;
then 3 characters for week day;
, is always there;
space is always there;
then 3 characters for month name;
space is always there;
day of month (one or two numbers);
, is always there;
space is always there;
4 numbers for year;
space at space always there;
time (have to match 4:39 as well as 10:39);
space and 2 caps letters for AM or PM.
Here's a very simple and readable one:
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{2} [AP]M/
See it on rubular
Try this:
On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), (?:Jan|Feb|Mar|Apr|May|June|July|Aug|Sept|Oct|Nov|Dec) \d{1,2}, \d{4} at \d{1,2}:\d{2} (?:AM|PM)
/On \w{3}, \w{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2} [A-Z]{2}/
# \w{3} for 3 charecters
# \d{1,2} for a or 2 digits
# \d{4} for 4 digits
# [A-Z]{2} for 2 capital leters
You could try the below regex and it won't check for the month name or day name or date.
^On\s[A-Z][a-z]{2},\s[A-Z][a-z]{2}\s\d{1,2},\s\d{4}\sat\s(?:10|4):39\s[AP]M$
DEMO
You can use Rubular to construct and test Ruby Regular Expressions.
I have put together an Example: http://rubular.com/r/45RIiwheqs
Since it looks you try to parse dates, you should use Date.strptime.
/On [A-Za-z]{3}, [A-Za-z]{3} \d{1,2}, \d{4} at \d{1,2}:\d{1,2}/g
The way you are describing the problem makes me thing that the format will always be preserved.
I would then in your case use the Time.parse function, passing the format string
format = "On %a, %b"On Fri, Jan 16, 2015 at 4:39 PM", format)
which is more readable than a regexp (in my opinion) and has the added value that it returns a Time object, which is easier to use than a regexp match, in case you need to perform other time-based calculations.
Another good thing is that if the string contains an invalid date (like "On Mon, Jan 59, 2015 at 37:99 GX" ) the parse function will raise an exception, so that validation is done for free for you.