All,
I have the following output from a command that I run in Perl. However, I am only interested in capturing the components and their respective statuses. (I.e. the "component" and "status" columns)
I've been thinking about how to approach this using regular expressions. I would like to assume that i will not really know the names of the components as in the future there may be additional components in the column. I don't care about the two middle columns (process-type or pid).
Any suggestions would be helpful.
my $consoleStatus = opmnctl status 2>&1;
-------------------+--------------------+---------+---------
component | process-type | pid | status
-------------------+--------------------+---------+---------
serverpro | logloaderd | N/A | Down
www-daemon | www-daemon | 10000 | Alive
OXQA | oqa | 99894 | Alive
SDFW | OC4X_SECURITY | 27683 | Alive
FTP_Servers | HTTP_Server | 21252 | Alive
OID | OID | 27207 | Alive
DSA | DSA | N/A | Down
Regards,
Assuming the layout of your output doesn't change, the component name doesn't have spaces, and the possible status are only 'Alive' and 'Down', you could use the given regex to match each line:
/^(\S+)\s+\|.+\|\s+(Alive|Down)$/
Below, I wrote a code that gets the input from STDIN, and prints out the component and it's status:
while(<STDIN>) {
if( $_ =~ /^(\S+)\s+\|.+\|\s+(Alive|Down)$/ ) {
print "$1 -> $2\n";
}
}
You might be able to use opmnctl options to simplify what the Perl has to process, maybe:
opmnctl status -noheaders -fsep '|' -fmt %cmp%sta
I'd suggest using split, and split on the pipe | characters that delimit the fields.
Here's a short snippet that may give you some ideas. If you can use some opmnctl options, you'd be able to simplify this.
use strict;
use warnings;
use Data::Dumper;
my %component_status;
LINE: for ( split( /\n/, $consoleStatus ) ) {
# Skip the furniture in the opmnctl output
next LINE if m/^component\W/ || m/^-/;
# field 0 is the component, field 3 the status.
my ( $component, $status ) = (split( / +\| */, $_ ))[0,3];
$component_status{$component} = $status;
}
warn Dumper( \%component_status );
Result:
$VAR1 = {
'DSA' => 'Down',
'FTP_Servers' => 'Alive',
'SDFW' => 'Alive',
'serverpro' => 'Down',
'OID' => 'Alive',
'OXQA' => 'Alive',
'www-daemon' => 'Alive'
};
Related
I'm trying to take the value of free space from a drive, this is necessary to do an automatict procedure in a database server.
I got this script:
$query_drive_mount_point = #"
select distinct
convert(varchar(512), b.volume_mount_point) as [volume],
convert(varchar(512), b.logical_volume_name) as [logical_volume]
from sys.master_files as [a]
CROSS APPLY sys.dm_os_volume_stats(a.database_id, a.[file_id]) as [b]
"#
[regex]$get_drive = '\w\:\\'
[regex]$get_drive_name = '\w'
[regex]$get_drive_space = '\d'
$mount_point = Invoke-Sqlcmd -ServerInstance "$server_ip\$sql_engine,$sql_port" -Username "$sql_user" -Password "$sql_password" -Database Master -Query "$query_drive_mount_point"
$get_disk = $get_drive.Matches($mount_point) | Foreach-Object {$_.Value}
$get_disk_name = $get_drive_name.Matches($get_disk) | Foreach-Object {$_.Value}
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -Property Free
[int]$size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach-Object {$_.Value}
$size_giga = ( ( ( $size_bytes )/1024 )/1024 )/1024
This code runs without problem until this line:
[int]$size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach-Object {$_.Value}
It throws this error:
There was not found overload for "Matches" and args numbers is "1".
En línea: 1 Carácter: 1
+ $size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach- ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
The last error is a traduction made by me, the os is in spanish.
Again, the objective is to store only the free space value.
You need to select the value from the property you need, so this line:
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -Property Free to
Should be changed to the following:
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -ExpandProperty Free
Alternatively you can format it as follows:
($size_bytes_string = Get-PSDrive $get_disk_name).Free
If you have PS version 5:
PS C:\> (($PSVersionTable).PSVersion)
Major Minor Build Revision
----- ----- ----- --------
5 1 18362 145
if not version 5, try to import the storage module.
You can get this information easier by using the below commandlet:
Get-disk # the command name
Get-Command -Module storage -Verb get -Noun disk # module
onliner code to select the size of the first hdd (disk 0):
[math]::Round((Get-Disk -Number 0).Size /1GB)
- Edited :
=========================================================================
if you load this assembly, you can get all the information you need,
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
$sql = New-Object ('Microsoft.SqlServer.Management.Smo.Server')
You can run this commandlet to find what information you can get :
(($sql | gm) | measure).count
For example :
write-host $dbs.Parent
$dbs=$s.Databases
I believe you need a property called filegroup to get information about ldf&mdf files.
I have a list of switches in CSV and a list of data spaces where these switches are. In my list of Data Spaces, I have a DataSpace_ID field which represents its associated DataSpace_Name.
My list of switches has a Host_Name and IP_Address fields. What I want is using PowerShell and regex matching using Wildcards, I want to match the DataSpace field example, "ABC-COM" to the switch listing Host_Name which would be ABC-COM-3750-SW1. I only want to match up to ABC-COM...
Then for my result I want the output, based on the matches found, to associate the DataSpace_ID value found and include it in the output of the switch listing.
Let's say I match ABC-COM = DATASPACE_ID 1 and DEF-COM = DataSpace_ID 2, and my switch data is:
Host_Name IP_Address
ABC-COM-3750-SW1 IP 192.168.1.2
ABC-COM-3750-SW2 IP: 192.168.1.3
DEF-COM-3750-SW1 IP: 192.168.3.5
DEF-COM-3750-SW2 IP: 192.168.3.6
So, in the end you would have this output from the switch listing based on comparison of the dataspace listing, except it would add the DataSpace_ID Column from the other comparison listing of data space names... Switch listing Output would look like this:
DataSpace_ID Host_Name IP_Address
1 ABC-COM-3750-SW1 IP 192.168.1.2
1 ABC-COM-3750-SW2 IP: 192.168.1.3
2 DEF-COM-3750-SW1 IP: 192.168.3.5
2 DEF-COM-3750-SW2 IP: 192.168.3.6
Here is my latest code revised based on some of your input, I am not getting errors any longer, however my output is not returning any results either.
clear-host
$hash.clear()
$dataSpacesExport = Import-Csv -Path .\DataSpaces_Export.csv -Header 'DataSpace_ID', 'DataSpace_Name' -Delimiter ","
$accessSwitchesForExport = Import-Csv -Path .\AccessSwitchesForExport.csv -Header 'Host_Name', 'IP_Address' -Delimiter ","
# create hashtable
$hash = #{}
# Create Regex criteria
$re = [regex]".+(?=-\d+)"
$dataSpacesExport | ConvertFrom-Csv | % { $hash.Add($_,”$_”) }
# output
$accessSwitchesForExport | ConvertFrom-Csv |
Select-Object #{ n = "DataSpace_ID"; e = { $hash[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null }
My CSV files as some have asked for, example data would be:
DataSpaces and switches output examples are below in the post. DataSpaces contain a DataSpace_ID and DataSpace_Name, and switches csv contain a Host_Name and IP_Address fields.
Output, like below, based on comparison of two csv's should show:
Matching DataSpace_ID with matching Host_Name, and its associated IP Address in final table.
This is a solution using a hash table.
$dataSpacesExport = #"
DataSpace_ID,DataSpace_Name
1,ABC-COM
2,DEF-COM
"#
$accessSwitchesForExport = #"
Host_Name,IP_Address
ABC-COM-3750-SW1,IP: 192.168.1.2
ABC-COM-3750-SW2,IP: 192.168.1.3
DEF-COM-3750-SW1,IP: 192.168.3.5
DEF-COM-3750-SW2,IP: 192.168.3.6
GHI-COM-3750-SW2,IP: 192.168.3.6
"#
$re = [regex]".+(?=-\d+)"
# create hashtable
$id = #{}
$dataSpacesExport | ConvertFrom-Csv | ForEach-Object { $id[$_.DataSpace_Name] = $_.DataSpace_ID }
# output
$accessSwitchesForExport | ConvertFrom-Csv |
Select-Object #{ n = "DataSpace_ID"; e = { $id[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null }
The output is as follows.
DataSpace_ID Host_Name IP_Address
------------ --------- ----------
1 ABC-COM-3750-SW1 IP: 192.168.1.2
1 ABC-COM-3750-SW2 IP: 192.168.1.3
2 DEF-COM-3750-SW1 IP: 192.168.3.5
2 DEF-COM-3750-SW2 IP: 192.168.3.6
The following code is another solution. In this case, you do not need a regular expression.
$dataSpaces = $dataSpacesExport | ConvertFrom-Csv
$accessSwitchesForExport | ConvertFrom-Csv | ForEach-Object {
foreach ($ds in $dataSpaces) {
if (!$_.Host_Name.StartsWith($ds.DataSpace_Name)) { continue }
[pscustomobject]#{
DataSpace_ID = $ds.DataSpace_ID
Host_Name = $_.Host_Name
IP_Address = $_.IP_Address
}
break
}
}
Thank you everyone for your help! I used bits and pieces of the recommendations above to come up with the following result which works perfectly and generates that data needed.
#Set Present Working Directory for path to save data to.
#Clear any Hash Table Data prior to start of script //
$id.clear()
#Import current listing of Data Spaces and Access switches from CSV format //
$dataSpacesExport = import-csv -Header DataSpace_ID, DataSpace_Name -Path ".\DataSpaces_Export.csv"
$accessSwitchesForExport = import-csv -Header Host_Name, Device_IP -Delimiter "," -Path ".\AccessSwitchesForExport.csv"
#Regex text matching criteria //
$re = [regex]".+(?=-\d+)"
# create hashtable to store output //
$id=#{}
# Inject DataSpaces listing into Script for processing via hash table $id //
$dataSpacesExport | % {$id[$_.DataSpace_Name] = $_.DataSpace_ID}
# output - Compare Access Switch listing to DataSpaces Hashtable information, produce output to out-file sw_names.txt //
$accessSwitchesForExport |
Select-Object #{ n = "DataSpace_ID"; e = { $id[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null } | Out-File ./sw_names.txt -Force
Output is as expected and is now working.
I'm not sure how to do this in a dataframe context
I have the table below here with text information
TEXT |
-------------------------------------------|
"Get some new #turbo #stacks today!" |
"Is it one or three? #phone" |
"Mayhaps it be three afterall..." |
"So many new issues with phone... #iphone" |
And I want to edit it down to where only the words with a '#' symbol are kept, like in the result below.
TEXT |
-----------------|
"#turbo #stacks" |
"#phone" |
"" |
"#iphone" |
In some cases, I'd also like to know if it's possible to eliminate the rows that are empty by checking for NaN as true or if you run a different kind of condition to get this result:
TEXT |
-----------------|
"#turbo #stacks" |
"#phone" |
"#iphone" |
Python 2.7 and pandas for this.
You could try using regex and extractall:
df.TEXT.str.extractall('(#\w+)').groupby(level=0)[0].apply(' '.join)
Output:
0 #turbo #stacks
1 #phone
3 #iphone
Name: 0, dtype: object
In OCaml, I have this piece of code:
let s =Sys.command ("minisat test.txt | grep 'SATIS' ");;
I want to take the output of minisat test.txt | grep "SATIS" , which is SATISFIABLE/UNSATISFIABLE to the string s.
I am getting the following output:
SATISFIABLE
val s : int = 0
So, how can I make the output of this command to a string.
Also, is it possible to even import time?
This is the output I get when I try minisat test.txt in terminal
WARNING: for repeatability, setting FPU to use double precision
============================[ Problem Statistics ]=============================
| |
| Number of variables: 5 |
| Number of clauses: 3 |
| Parse time: 0.00 s |
| Eliminated clauses: 0.00 Mb |
| Simplification time: 0.00 s |
| |
============================[ Search Statistics ]==============================
| Conflicts | ORIGINAL | LEARNT | Progress |
| | Vars Clauses Literals | Limit Clauses Lit/Cl | |
===============================================================================
===============================================================================
restarts : 1
conflicts : 0 (-nan /sec)
decisions : 1 (0.00 % random) (inf /sec)
propagations : 0 (-nan /sec)
conflict literals : 0 (-nan % deleted)
Memory used : 8.00 MB
CPU time : 0 s
SATISFIABLE
If you use just Sys, you can't.
However, you can create a temporary file (see the Filename module's documentation here) and tell the command to output in it:
let string_of_command () =
let tmp_file = Filename.temp_file "" ".txt" in
let _ = Sys.command ## "minisat test.txt | grep 'SATIS' >" ^ tmp_file in
let chan = open_in tmp_file in
let s = input_line chan in
close_in chan;
s
Note that this function is drafty: you have to properly handle potential errors happening. Anyway, you can adapt it to your needs I guess.
You can avoid the temporary file trick by using the Unix library or more advanced libraries.
You have to use Unix.open_process_in or Unix.create_process, if you want to capture the output.
Or better use a higher level wrapper like 'shell' (from ocamlnet):
http://projects.camlcity.org/projects/dl/ocamlnet-4.0.2/doc/html-main/Shell_intro.html
But I wouldn't pipe it to grep (not portable). Parse the output with your favorite regex library inside OCAML.
I'm trying to map a drive letter using this line of code which will give me a list of drives available from d to z.
ls function:[d-z]: -n | ? { !(test-path $_) }
I'd like to then pick the last letter, not random, from the list. How would I go about doing that? New to Powershell, thanks for the help.
You can use Select-Object -Last 1 at the end of that pipeline.
you can just start at the back of the list and go up.
last item: $array[-1]
Second to last: $array[-2]
and so on.
If you look for a much more verbose, but (in my opinion) readable-improved version:
# Get all drives which are used (unavailable)
# Filter for the "Name" property ==> Drive letter
$Drives = (Get-PSDrive -PSProvider FileSystem).Name
# Create an array of D to Z
# Haven't found a more elegant version...
$Letters = [char[]]([char]'D'..[char]'Z')
# Filter out, which $Letters are not in $Drives (<=)
# Again, filter for their letter
$Available = (Compare-Object -ReferenceObject $Letters -DifferenceObject $Drives | Where {$_.SideIndicator -eq "<="}).InputObject
# Get the last letter
$LastLetter = $Available[-1]
Try this:
ls function:[d-z]: -n|?{!(test-path $_)} | Select-Object -Last 1
Another option that doesn't require trying all paths from D-Z is to parse Get-Psdrive. Here's an example:
$lettersInUse = Get-Psdrive | ? { $_.Name.Length -eq 1 } | % { $_.Name }
$lastDriveLetter = [Char]'Z'
while ($lettersInUse -contains $lastDriveLetter) {
$lastDriveLetter = [Char]($lastDriveLetter - 1)
}
$lastDriveLetter
In case you have an array
$newArray = #(git tag --list)
$lastmember = $newArray[$newArray.Count – 1]
In case you have a list
$newArray | Select-Object -Last 1