How to select first tab-separated column in first line? - powershell-2.0

I would like to grep -o the date... only the first value in line 1 from a tab-separated file with PowerShell v2.
I used the following command to get the first line:
Get-Content "C:\filepath\file.txt" | select -first 1
How can get also the first column of this line? Or via Regex?
Sample:
15.03.2017 22:42:49 uSecAction = 4
15.03.2017 22:42:49 uAction_Program = 5
15.03.2017 22:42:49 uSecAction_Program = 4
Thanks in advance.

This snippet should help you to get the first column of the tab separated file :
Get-Content "d:\my docs\file.txt" |select -first 1| %{ ($_ -split "\t+")[0]}

Related

How to add text from two files in awk

I have two tab delim files as shown below:
FileA.txt
1 a,b,c
2 b,c,e
3 e,d,f,a
FileB.txt
a xxx
b xyx
c zxxy
I would need the output in the below way:
Output:
1 a,b,c xxx,xyx.zxxy
2 b,c,e xyx,zxxy,e
3 e,d,f,a e,d,f,xxx
The comma separated values in $2 of FileA are to be used as key to search for a match in $1 of FileB and add a new column in the output with their values in $2 from FileB. Incase of no match it should print the original value. Any help on how to do this?
awk to the rescue!
$ awk 'NR==FNR {a[$1]=$2; next}
{NF++; s=""; n=split($2,t,",");
for(i=1;i<=n;i++) {k=t[i];
$NF=$NF s ((k in a)?a[k]:k);
s=","}}1' fileB fileA | column -t
1 a,b,c xxx,xyx,zxxy
2 b,c,e xyx,zxxy,e
3 e,d,f,a e,d,f,xxx

PowerShell Parse INF file

I am trying to parse an INF; specifically, driver version from the file. I am new to PowerShell, so I've gotten only this far.
The file looks like this:
[Version]
Signature = "$WINDOWS NT$"
Class = Bluetooth
ClassGuid = {e0cbf06c-cd8b-4647-bb8a-263b43f0f974}
Provider = %PROVIDER_NAME%
CatalogFile = ibtusb.cat
DriverVer=11/04/2014,17.1.1440.02
CatalogFile=ibtusb.cat
The second last line has the information I am looking for. I am trying to parse out just 17.1.1440.02.
One file may contain multiple lines with DriverVer=..., but I am only interested in the first instance.
Right now I've the following script.
$path = "C:\FilePath\file.inf"
$driverVersoin = Select-String -Pattern "DriverVer" -path $path
$driverVersoin[0] # lists only first instance of 'DriverVer'
$driverVersoin # lists all of the instances with 'DriverVer'
Output is:
Filepath\file.inf:7:DriverVer=11/04/2014,17.1.1440.02
But I am only looking for 17.1.1440.02
Make your expression more specific and make the part you want to extract a capturing group.
$pattern = 'DriverVer\s*=\s*(?:\d+/\d+/\d+,)?(.*)'
Select-String -Pattern $pattern -Path $path |
select -Expand Matches -First 1 |
% { $_.Groups[1].Value }
Regular expression breakdown:
DriverVer\s*=\s* matches the string "DriverVer" followed by any amount of whitespace, an equals sign and again any amount of whitespace.
(?:\d+/\d+/\d+,)? matches an optional date followed by a comma in a non-capturing group ((?:...)).
(.*) matches the rest of the line, i.e. the version number you want to extract. The parentheses without the ?: make it a capturing group.
Another option (if the version number is always preceded by a date) would be to just split the line at the comma and select the last field (index -1):
Get-Content $path |
Where-Object { $_ -like 'DriverVer*' } |
Select-Object -First 1 |
ForEach-Object { $_.Split(',')[-1] }

Given repeating sections, how do I find sections matching certain criteria using Powershell

I need to parse a text file and retrieve data from it... based on other data in the same file..
I need to find the lines that say not ok.. and then find the Nodes they are under..
I know how to pull the data in..and find the Not Ok's and the Nodes. I also have an idea that I'm sure is overly complicated to find what I'm looking for. I can parse the Node lines into an array so like
$test = (select-string -path C:\error.txt -Pattern "Node:").linenumber
then find the line number of the not oks and backup lol but this seems like the most difficult way to do this. I'm familiar with PS but not an expert.
$test2 = (select-string -path C:\error.txt -Pattern "Not ok").linenumber
so to spell out what I need ..
parse file for Node.. find lines below that are not ok.. and if so set node to variable...if not ok isn't found move on to next node.
Thanks for any help
example txt file below
Node: Server
*********************
Line 1 ok
line 2 ok
line 3 ok
Line 4 Not ok
line 5 ok
line 6 ok
*********************
Node: Server2
*********************
Line 1 ok
line 2 ok
line 3 Not ok
Line 4 ok
line 5 ok
line 6 ok
*********************
$errorNodes = #()
Get-Content C:\temp\test.txt | ForEach-Object {
if ($_ -imatch 'Node: (.+)$') {
$node = $Matches[1]
}
if ($_ -imatch 'not ok') {
$errorNodes += $node
}
}
$errorNodes
Explanation
Get-Content reads a file line by line.
For each line, first check to see if it's a node; if so, set the $node variable to the current node's name.
Then check to see if the line matches the text 'not ok'. If so, add the node name to the list of error nodes (the array variable $errorNodes.
So at the end, $errorNodes will contain the nodes with problems.
If your list is long, this should be a quicker way to parse (also less code :)):
$nodes = [Regex]::Split((Get-Content info.txt), 'Node:')
# '?' is an alias for Where-Object
$bad = $nodes | ? { $_.ToLower().Contains('not ok') }
$bad now also contains all the text under the node containing "not ok" (in the even there are multiple lines that are not ok).
This answer is most likely more complicated than it needs to be but it returns useful objects that, depending what else op needs to do in his code, can be useful for further processing. For this example I used the file structure of the OP and added some extra nodes to make the output a little more verbose.
$file = Get-Content "c:\temp\test.txt" -Raw
$file -split '\s+(?=Node: \w+)' |
%{ $stringData = (($_ -replace ": "," = ") -replace 'line\W+(\d+)\W+','Line$1 = ') -replace '\*+'
New-Object PSObject -Property $(ConvertFrom-StringData $Stringdata)
} | select node,line* | Format-Table
Using PowerShell 3.0: The code will read the file as a whole string (Not creating a string array) using the -Raw parameter. The $file is the string split at the text "Node: " which will break up the Nodes as separate objects.
In order to create the custom object we need to make sure all the items of the Node contain name=value pairs. To accomplish this I nested some -replace operations.
$_ -replace ": "," = " - To change the first line to "Node = Servername"
-replace 'line\W+(\d+)\W+','Line$1 = ' - Convert Line # ok into Line# = Ok\Not Ok Where # is the particular line 1-6
-replace '\*+' - To remove the lines that contain just astericks ( or whatever the plural of astericks is)
The formated string is used as input for New-Object PSObject -Property $(ConvertFrom-StringData $Stringdata)
After that we can control the piped output like we would almost any other object. To ensure that node appears first in the list the select-object statement.
The following is my sample output:
Node Line4 Line5 Line6 Line1 Line2 Line3
---- ----- ----- ----- ----- ----- -----
Server Not ok ok ok ok ok ok
Server2 ok ok ok ok ok Not ok
Server4 ok ok ok Not ok ok ok
Server3 ok ok ok ok ok ok

How to print un join lines using join command or awk?

join command prints 2 common strings in 2 files. But is there any way to print the strings that did't match ?
file 1
a 1
b 2
c 3
file2
a 3
b 3
output
c 3
Using join command:
join -a1 -v1 file1 file2
-a1 = print non-matching lines of first file. -v to suppress normal output
To join on the first field, here's one way using awk:
awk 'FNR==NR { a[$1]; next } !($1 in a)' file2 file1
Results:
c 3

Use grep -A1 to return a value in the second line as long as a numeric value in the first line is met

I have log entries that are paired two lines each. I have to parse the first line to extract
a number to know if it is greater than 5000. If this number is greater than 5000 then I need to return the second line, which will also be parsed to retrieve an ID.
I know how to grep all of the info and to parse it. I don't know how to make the grep ignore
things if they are less than a particular value. Note that I am not committed to using grep if some
other means like awk/sed can be substituted.
Raw Data (two lines separated for example clarity).
The target of my grep is the number 5001
following "credits extracted = ", if this is over 5000 then I want to return number "12345" from
the second line --------------------------
2012-03-16T23:26:12.082358 0x214d000 DEBUG ClientExtractAttachmentsPlayerMailTask for envelope 22334455 finished: credits extracted = 5001, items extracted count = 0, status = 0. [Mail.heomega.mail.Mail](PlayerMailTasks.cpp:OnExtractAttachmentsResponse:944)
2012-03-16T23:26:12.082384 0x214d000 DEBUG Mail Cache found cached mailbox for: 12345 [Mail.heomega.mail.Mail](MailCache.cpp:GetCachedMailbox:772)
Snippits --------------------------
-- Find the number of credits extracted, without the comma noise:
grep "credits extracted = " fileName.log | awk '{print $12}' | awk -F',' '{print $1}'
-- Find the second line's ID no matter what the value of credits extracted is:
grep -A1 "credits extracted = " fileName.log | grep "cached mailbox for" | awk -F, '{print $1}' | awk '{print $10}'
-- An 'if' statement symbolizing the logic I need to acquire:
v_CredExtr=5001; v_ID=12345; if [ $v_Cred -gt 5000 ]; then echo $v_ID; fi;
You can do everything with a single AWK filter I believe:
#!/usr/bin/awk -f
/credits extracted =/ {
credits = substr($12, 1, length($12) - 1) + 0
if (credits > 5000)
show_id = 1
next
}
show_id == 1 {
print $10
show_id = 0
}
Obviously, you can stuff all the AWK script in a shell string inside a script, even multiline. I showed it here in its own script for clarity.
P.S: Please notify when it works ;-)

Resources