Confusion on grep pattern search - regex

Consider this log file
SN PID Date Status
1 P01 Fri Feb 14 19:32:36 IST 2014 Alive
2 P02 Fri Feb 14 19:32:36 IST 2014 Alive
3 P03 Fri Feb 14 19:32:36 IST 2014 Alive
4 P04 Fri Feb 14 19:32:36 IST 2014 Alive
5 P05 Fri Feb 14 19:32:36 IST 2014 Alive
6 P06 Fri Feb 14 19:32:36 IST 2014 Alive
7 P07 Fri Feb 14 19:32:36 IST 2014 Alive
8 P08 Fri Feb 14 19:32:36 IST 2014 Alive
9 P09 Fri Feb 14 19:32:36 IST 2014 Alive
10 P010 Fri Feb 14 19:32:36 IST 2014 Alive
When i do => grep "P01" File
output is : (as expected)
1 P01 Fri Feb 14 19:32:36 IST 2014 Alive
10 P010 Fri Feb 14 19:32:36 IST 2014 Alive
But when i do => grep " P01 " File (notice the space before and after P01)
I do not get any output!
Question : grep matches pattern in a line, so " P01 " ( with space around ) should match the first PID of P01 as it has spaces around it....but seems that this logic is wrong....what obvious thing i am missing here!!!?

If the log uses tabs not spaces, your grep pattern won't match. I would add word boundaries to the word you want to find:
grep '\<P01\>' file
If you really want to use whitespace in your pattern, use one of:
grep '[[:blank:]]P01[[:blank:]]' file # horizontal whitespace, tabs and spaces
grep -P '\sP01\s' file # using Perl regex

Related

AWS cron expression to run every other Monday

I want to schedule a CloudWatch event to run every other Monday and have started with this command:
0 14 ? * 2 *
Currently with the above command, I get a weekly schedule of Monday executions:
Mon, 27 Jul 2020 14:00:00 GMT
Mon, 03 Aug 2020 14:00:00 GMT
Mon, 10 Aug 2020 14:00:00 GMT
Mon, 17 Aug 2020 14:00:00 GMT
Mon, 24 Aug 2020 14:00:00 GMT
Mon, 31 Aug 2020 14:00:00 GMT
Mon, 07 Sep 2020 14:00:00 GMT
Mon, 14 Sep 2020 14:00:00 GMT
Mon, 21 Sep 2020 14:00:00 GMT
Mon, 28 Sep 2020 14:00:00 GMT
However, I would like the schedule to be set to every other Monday, e.g.
Mon, 27 Jul 2020 14:00:00 GMT
Mon, 10 Aug 2020 14:00:00 GMT
Mon, 24 Aug 2020 14:00:00 GMT
Mon, 07 Sep 2020 14:00:00 GMT
Mon, 21 Sep 2020 14:00:00 GMT
I have seen examples with exp and # being used, but I don't think AWS CloudWatch events accept these sort of parameters.
Chris' answer is correct. Currently, there is no way that I could think of to express this as part of CloudWatch Scheduled Events.
However, a workaround could be to set it to every Monday (0 14 ? * 2 *) and trigger a Lambda function that checks whether it's in the on-week or the off-week before triggering the actual target.
Even though this adds some complexity, it would be a viable solution.
You won't be able to do any of the fancier commands (especially those using variables from the command line).
You could do this very basically but would require 2 separate events in order to carry it out:
0 14 ? * 2#1 * - Run on the first Monday of the month.
0 14 ? * 2#3 * - Run on the third Monday of the month.
Unfortunately there is no compatible syntax for scheduled expressions that would allow the concept of every other week, so the above commands occasionally could lead to a 3 week gap.
If you don't care about the Monday you could of course use 0 14 1,15 * * to run on the 1st and 15th of each month (roughly every 2 weeks).
The final option would be to run every Monday, but have the script exit if it is not the every other week, the expression would then just be 0 14 ? * 2 *.
More information about the syntax is available on the Cron Expressions section of the Scheduled Events page.

Print the first line occurrence of each matching pattern with sed

I would like to filter the output of the utility last based on a variable set of usernames.
This is sample output from last unfiltered,
reboot system boot server Wed Apr 6 13:15 - 14:24 (01:09)
user1 pts/0 server Wed Apr 6 13:08 - 13:15 (00:06)
reboot system boot system Wed Apr 6 13:08 - 13:15 (00:06)
user1 pts/0 server Wed Apr 6 13:06 - down (00:01)
reboot system boot system Wed Apr 6 13:06 - 13:07 (00:01)
user1 pts/0 server Wed Apr 6 12:59 - down (00:06)
What I would like to do is pipe the output of last to sed. Then, using sed I would print the first occurrence of each specified user name i.e. their last log entry in wtmp. The output should appear as so,
reboot system boot server Wed Apr 6 13:15 - 14:24 (01:09)
user1 pts/0 server Wed Apr 6 13:08 - 13:15 (00:06)
The sed expression that I particularly like is,
last|sed '/user1/{p;q;}'
Unfortunately this only gives me the ability to match the first occurrence of one username. Using this syntax is there a way I could specify a multiple of usernames? Thanks in advance!
awk is better fit here than sed due to awk's ability to use associative arrays:
last | awk '!seen[$1]++'
reboot system boot server Wed Apr 6 13:15 - 14:24 (01:09)
user1 pts/0 server Wed Apr 6 13:08 - 13:15 (00:06)

Regexp (not in string) in perl

Okie, I have the following files:
total 32
drwxr-xr-x 12 al staff 408B Feb 28 11:36 ./
drwxr-xr-x+ 40 al staff 1.3K Feb 28 10:07 ../
drwxr-xr-x 3 al staff 102B Oct 19 20:38 Install OS X Yosemite.app/
-rw-r--r-- 1 al staff 7B Dec 15 13:35 file1
-rw-r--r-- 1 al staff 4B Dec 15 13:35 file2
-rw-r--r-- 1 al staff 11B Dec 15 13:35 file3.part
-rw-r--r-- 1 al staff 0B Feb 28 11:36 file4.art
-rwxr-xr-x 1 al staff 1.9K Feb 28 11:35 show.pl*
drwxr-xr-x 2 al staff 68B Feb 28 10:07 test1/
drwxr-xr-x 6 al staff 204B Feb 28 10:12 test2/
drwxr-xr-x 3 al staff 102B Feb 28 10:07 test3/
drwxr-xr-x 3 al staff 102B Feb 28 10:12 test4/
Now I need a regexp that will do the following:
3 or more characters (to omit . and ..) of any type NOT ending in the string .part (but ending in anything else is OK).
The following almost works, but it will not match .app and .art (which it should).
print $file =~ m/^.{3,}[^(\.part)]$/i;
And please believe me when I say... I have TRIED (for a loooong time)
You need to use a negative lookahead assertion at the start.
print $file =~ m/^(?!.*\.part$).{3,}/i;
DEMO
Asserts that the string going to be matched won't contain .part string at the last. If yes, then match the string which has three or more characters. $ asserts that we are at the end.

How can I set x-axis values in the Area Chart google visualisation

I am using Area chart by google visualisation. I need to customise the x-axis values.for example the date starts from 1 oct to 2 dec. In this I need to display only 10 values which includes the start date and the end date.
By default it displays like this.
oct 1 oct 2 oct 3 oct 4 oct 5 oct 6 oct 7 oct 8 oct 9 oct 10
But I need in this format.
oct 1 oct 7 oct 14 oct 21 oct 28 nov 4 nov 11 nov 18 nov 25 dec 2
and the values in between i.e., from start date to end date can be anything.
Any suggestions?
Thank you in advance
You can do one thing. Get input the start date and end date well then calculate its difference. After getting the difference divide it in 10 intervals. Then assign these 10 intervals to the x-axis value.

How to implement a 96 conditions wisely?

I'm trying to write a program in c++ which produce a report, which provide a report on the usage by time. Break the time into blocks of quarter of an hour
00:00-00:14, 00:15-00:29, …, 23:45-23:59.
I should provide number of incidents in each time break. This is my code so far. I appreciate if anyone come up with a solution.
string time = word;
size_t found2 = word.find(":");
string tmpH,tmpM;
tmpH = word.substr(0,found2);
tmpM = word.substr((found2+1),word.length());
cout<<" word= "<<word<<" tmpH= "<<tmpH<<" tmpM= "<<tmpM<<endl;
int h = atoi(tmpH.c_str());
int m = atoi(tmpM.c_str());
////
Input:
aa784 pts/30 Fri Mar 28 03:25 still logged in 101.175.22.198
aa784 sshd Fri Mar 28 03:25 still logged in 101.175.22.198
aa784 pts/30 Fri Mar 28 03:25 - 03:25 (00:00) 101.175.22.198
aa784 sshd Fri Mar 28 03:25 - 03:25 (00:00) 101.175.22.198
hmb183 sshd Fri Mar 28 03:24 still logged in c110-20-244-248.mirnd4.nsw.optusnet.com.au
bkg988 sshd Fri Mar 28 03:24 - 03:24 (00:00) 139.218.157.100
hmb183 sshd Fri Mar 28 03:21 - 03:22 (00:01) c110-20-244-248.mirnd4.nsw.optusnet.com.au
fmm290 pts/43 Fri Mar 28 03:11 still logged in 1002-wan-001.rhw.com.au
fmm290 sshd Fri Mar 28 03:11 still logged in 1002-wan-001.rhw.com.au
bkg988 sshd Fri Mar 28 03:09 - 03:09 (00:00) 139.218.157.100
pm554 pts/14 Fri Mar 28 02:22 still logged in ppp239-204.static.internode.on.net
pm554 sshd Fri Mar 28 02:22 still logged in ppp239-204.static.internode.on.net
bkg988 sshd Fri Mar 28 02:17 - 02:17 (00:00) 139.218.157.100
bkg988 sshd Fri Mar 28 02:12 - 02:12 (00:00) 139.218.157.100
bkg988 sshd Fri Mar 28 02:10 - 02:10 (00:00) 139.218.157.100
bx972 pts/12 Fri Mar 28 02:09 still logged in cpe-121-218-195-236.lnse4.cht.bigpond.net.au
bkg988 sshd Fri Mar 28 02:07 - 02:07 (00:00) 139.218.157.100
hmb183 sshd Fri Mar 28 02:05 - 02:06 (00:01) c110-20-244-248.mirnd4.nsw.optusnet.com.au
bkg988 sshd Fri Mar 28 02:04 - 02:04 (00:00) 139.218.157.100
output:
00:00-00:14 10 users logged in
00:15-00:29 15 users logged in
....
23:45-23:59 3 users logged in
Therefore I have 4 conditions in an hour which comes to 96 conditions of time?
First, you can convert each block of hour and minute into minutes , for example 23:45 equals 1095 in minutes. Storing all of these blocks into a list and sort them by its starting time.
For each event, convert each event time into number of minute and use binary search(or linear search) to search for a block that has largest starting time less than or equals to the event time,and that block will be the block this event belong to.
Time complexity to sort is O(1) as there is only few block, and, for all query will be O(n), with n is the number of query.(Binary search in this case can be considered take constant time).
Edit: As you have added another constraint, so , you need to sort all the event by date and time, and for each date, you can use the described approach.
Given lines like:
bkg988 sshd Fri Mar 28 02:17 - 02:17 (00:00) 139.218.157.100
You can do this:
std::string to_month_number(const std::string& name)
{
return name == "Jan" ? "01/" :
name == "Feb" ? "02/" :
...;
}
typedef std::pair<std::string, int> When;
typedef std::map<When, int> Num_Logins;
Num_Logins num_logins;
std::string user, term, day, month, dom;
int hour, min;
char c;
while (std::cin >> user >> term >> dow >> month >> dom >> hour >> c >> min && c == ':')
{
if (dom.length() == 1) dom = ' ' + dom; // standardise with for sorting...
When when = std::make_pair(to_month_number(month) + ' ' + dom, (hour * 60 + min) / 15);
++num_logins[when];
}
I suspect the actual input will be a bit more complex, with the date being formatted differently when the process started last year or intraday, so you'll need to tune the fields parsed out. To recreate the time when iterating over num_logins to print out results, just:
int hour = key->second / 4;
int min = (key->second % 4) * 15; // 00, 15, 30 or 45