Can someone tell me what I'm doing wrong in my regexp statement? It doesn't match the "Operability: Degraded" line. I am trying to match anything that is not in operable state. I am new to TCL. Thanks!
Contents of $expect_out(buffer) it does the regexp on:
ID 20:
Location: G1
Presence: Equipped
Overall Status: Operable
Operability: Degraded
Visibility: Yes
Product Name: 16GB DDR3-1600-MHz RDIMM/PC3-12800/dual rank/1.35V
PID:
VID: V01
Vendor: 0x2C00
Vendor Description: Micron Technology, Inc.
Vendor Part Number:
Vendor Serial (SN):
HW Revision: 0
Form Factor: DIMM
Type: DDR3
Capacity (MB): 16384
Clock: 1600
Latency: 0.600000
Width: 64
Code:
proc check_errors { buffer cmd } {
set count [ regexp -all -- { Activate-Status.*?!Ready|Overall.*Status.*?!Operable|Operability.*?!Operable|Controller.*Status.*?!Optimal|Errors.*?!0|Dr
opped.*?!0|Discarded.*?!0|Bad.*?!0|Suspect.*?!No|Thresholded.*?!0|Visibility.*?!Yes|Thermal.*Status.*?!OK|HA.*?!READY } $buffer ]
if { [ set count ] != 0 } {
puts "\tFAIL $cmd (Error Count: $count)"
} else {
puts "\tPASS $cmd"
}
}
Output: (blade 6/5 has a known issue, it should fail the memory check)
Blade 6/5 checks...
PASS show stats
PASS show version
PASS show adapter detail
PASS show cpu detail
PASS show memory detail
PASS show inventory detail
!term doesn't mean "anything but term" in regex. For that type of logic, you'll need a negative lookahead approach:
Activate-Status(?!.*Ready)|Overall.*Status(?!.*Operable)|Operability(?!.*Operable)|Controller.*Status(?!.*Optimal)|Errors(?!.*0)|Dropped(?!.*0)|Discarded(?!.*0)|Bad(?!.*0)|Suspect(?!.*No)|Thresholded(?!.*0)|Visibility.(?!.*yes)|Thermal.*Status(?!.*OK)|HA.*(?!.*READY)
check it out here
note: I'd use case insensitivity to filter out both "No" and "no", and also, you must make sure your input is not treated as a single line, but multiple lines, so the .* wildcards don't race past the \n newlines and mess everything up.
#sweaver2112 has the right answer. I'd like to add maintainability into the mix:
use the -expanded flag for additional non-meaningful whitespace
use the -line so . does not match a newline (so "Ready" is on the same line as "Activate-Status")
-nocase for case-insensitive matching (if that's important)
set count [ regexp -all -expanded -line -- {
Activate-Status (?!.*?Ready) |
Overall.*Status (?!.*?Operable) |
Operability (?!.*?Operable) |
Controller.*Status (?!.*?Optimal) |
Errors (?!.*?0) |
Dropped (?!.*?0) |
Discarded (?!.*?0) |
Bad (?!.*?0) |
Suspect (?!.*?No) |
Thresholded (?!.*?0) |
Visibility (?!.*?Yes) |
Thermal.*Status (?!.*?OK) |
HA (?!.*?READY)
} $buffer ]
Related
I want to write PowerShell script and regex to audit several network devices configuration files for compliance. Some devices are configured one management vlan while others have multiple different management vlans. Examples below
Config1:
VLAN Name Status Ports
1 default active
100 12_NET_MGMT_VLAN active Gi1/2
Config2:
VLAN Name Status Ports
1 default active
88 100_MGMT-VLLAN active Gi8/1
100 12_Net_MGMT_VLAN active
If I hard code the regex pattern like this $regex_pattern = "^\d{1,3}\s+.*MGMT.*", I got the corrected output as expected
Config1 12_NET_MGMT_VLAN
Config2 100_MGMT_VLAN
Config2 12_Net_MGMT_VLAN
Instead of hard-code the regex pattern, I want to use the Read-Host cmdlet and ask a user to enter the word "MGMT" and store it in a variable $Mgmt, then concatenate with a regex pattern to create a dynamic regex pattern, like this:
$Mgmt = Read-Host "Enter a word pattern to find a management vlan: "
For example, a user type in MGMT, and then I created a dynamic regex pattern as below:
$regex_pattern = "^\d{1,3}\s+.*"+$Mgmt+"_.*"
$regex_pattern = "^\d{1,3}\s+.*"+[regex]::escape($Mgmt)+".*"
None of the results came out correct
If anyone has a solution, please help. Thx
If we are to assume that VLAN names cannot contain spaces, you can use \S (non-space) as an anchor character. Using the subexpression operator $(), you can evaluate an expression within a string.
# Simulating a vlan config output
$Config = #'
VLAN Name Status Ports
1 default active
88 100_MGMT-VLLAN active Gi8/1
100 12_Net_MGMT_VLAN active
'# -split '\r?\n'
# Using value MGMT here when prompted
$Mgmt = Read-Host "Enter a word pattern to find a management vlan"
$regex = "\S*$([regex]::Escape($Mgmt))\S*"
[regex]::Matches($Config,$regex).Value
Output:
100_MGMT-VLLAN
12_Net_MGMT_VLAN
Note that simple variable references like $Mgmt will expand properly within surrounding double quotes, e.g. "My VLAN is $Mgmt".
You could take this in a different direction and create a custom object from your output. This would enable you to use filtering via Where-Object and member access (.Property) to retrieve target data. This again assumes values don't contain spaces.
# Simulating a vlan config output
$Config = #'
VLAN Name Status Ports
1 default active
88 100_MGMT-VLLAN active Gi8/1
100 12_Net_MGMT_VLAN active
'# -split '\r?\n'
$Mgmt = Read-Host "Enter VLAN Name"
# Replacing consecutive spaces with , first
$ConfigObjs = $Config -replace '\s+',',' | ConvertFrom-Csv
$ConfigObjs
Output:
VLAN Name Status Ports
---- ---- ------ -----
1 default active
88 100_MGMT-VLLAN active Gi8/1
100 12_Net_MGMT_VLAN active
Now you have properties that can be referenced and access to other comparison operators so you don't always need to use regex.
($ConfigObjs | Where Name -like "*$Mgmt*").Name
Output:
100_MGMT-VLLAN
12_Net_MGMT_VLAN
Yet again my unfamiliarity with AWK lets me down, I can't figure out how to match a variable at the end of a line?
This would be fairly trivial with grep etc, but I'm interested in matching integers at the end of a string in a specific field of a tsv, and all the posts suggest (and I believe it to be the case!) that awk is the way to go.
If I want to just match a single one explicity, that's easy:
Here's my example file:
PVClopT_11 PAU_02102 PAU_02064 1pqx 1pqx_A 37.4 13 0.00035 31.4 >1pqx_A Conserved hypothetical protein; ZR18,structure, autostructure,spins,autoassign, northeast structural genomics consortium; NMR {Staphylococcus aureus subsp} SCOP: d.267.1.1 PDB: 2ffm_A 2m6q_A 2m8w_A No DOI found.
PVCpnf_18 PAK_3526 PAK_03186 3fxq 3fxq_A 99.7 2.7e-21 7e-26 122.2 >3fxq_A LYSR type regulator of TSAMBCD; transcriptional regulator, LTTR, TSAR, WHTH, DNA- transcription, transcription regulation; 1.85A {Comamonas testosteroni} PDB: 3fxr_A* 3fxu_A* 3fzj_A 3n6t_A 3n6u_A* 10.1111/j.1365-2958.2010.07043.x
PVCunit1_19 PAU_02807 PAU_02793 3kx6 3kx6_A 19.7 45 0.0012 31.3 >3kx6_A Fructose-bisphosphate aldolase; ssgcid, NIH, niaid, SBRI, UW, emerald biostructures, glycolysis, lyase, STRU genomics; HET: CIT; 2.10A {Babesia bovis} No DOI found.
PVClumt_17 PAU_02231 PAU_02190 3lfh 3lfh_A 39.7 12 0.0003 28.9 >3lfh_A Manxa, phosphotransferase system, mannose/fructose-speci component IIA; PTS; 1.80A {Thermoanaerobacter tengcongensis} No DOI found.
PVCcif_11 plu2521 PLT_02558 3h2t 3h2t_A 96.6 2.6e-05 6.7e-10 79.0 >3h2t_A Baseplate structural protein GP6; viral protein, virion; 3.20A {Enterobacteria phage T4} PDB: 3h3w_A 3h3y_A 10.1016/j.str.2009.04.005
PVCpnf_16 PAU_03338 PAU_03377 5jbr 5jbr_A 29.2 22 0.00058 23.9 >5jbr_A Uncharacterized protein BCAV_2135; structural genomics, PSI-biology, midwest center for structu genomics, MCSG, unknown function; 1.65A {Beutenbergia cavernae} No DOI found.
PVCunit1_17 PAK_2892 PAK_02622 1cii 1cii_A 63.2 2.7 6.9e-05 41.7 >1cii_A Colicin IA; bacteriocin, ION channel formation, transmembrane protein; 3.00A {Escherichia coli} SCOP: f.1.1.1 h.4.3.1 10.1038/385461a0
PVCunit1_11 PAK_2886 PAK_02616 3h2t 3h2t_A 96.6 1.9e-05 4.9e-10 79.9 >3h2t_A Baseplate structural protein GP6; viral protein, virion; 3.20A {Enterobacteria phage T4} PDB: 3h3w_A 3h3y_A 10.1016/j.str.2009.04.005
PVCpnf_11 PAU_03343 PAU_03382 3h2t 3h2t_A 97.4 4.4e-07 1.2e-11 89.7 >3h2t_A Baseplate structural protein GP6; viral protein, virion; 3.20A {Enterobacteria phage T4} PDB: 3h3w_A 3h3y_A 10.1016/j.str.2009.04.005
PVCunit1_5 afp5 PAU_02779 4tv4 4tv4_A 63.6 2.6 6.7e-05 30.5 >4tv4_A Uncharacterized protein; unknown function, ssgcid, virulence, structural genomics; 2.10A {Burkholderia pseudomallei} No DOI found.
And I can pull out all the lines which have a "_11" at the end of the first column by running the following on the commandline:
awk '{ if ($1 ~ /_11$/) { print } }' 02052017_HHresults_sorted.tsv
I want to enclose this in a loop to cover all integers from 1 - 5 (for instance), but I'm having trouble passing a variable in to the text match.
I expect it should be something like the following, but $i$ seems like its probably incorrect and by google-fu failed me:
awk 'BEGIN{ for (i=1;i<=5;i++){ if ($1 ~ /_$i$/) { print } } }' 02052017_HHresults_sorted.tsv
There may be other issues I haven't spotted with that awk command too, as I say, I'm not very awk-savvy.
EDIT FOR CLARIFICATION
I want to separate out all the matches, so can't use a character class. i.e. I want all the lines ending in "_1" in one file, then all the ones ending in "_2" in another, and so on (hence the loop).
You can't put variables inside //. Use string concatenation, which is done by simply putting the strings adjacent to each other in awk. You don't need to use a regexp literal when you use the ~ operator, it always treats the second argument as a regexp.
awk '{ for (i = 1; i <= 5; i++) {
if ( $1 ~ ("_" i "$") ) { print; break; }
}' 02052017_HHresults_sorted.tsv
It sounds like you're thinking about this all wrong and what you really need is just (with GNU awk for gensub()):
awk '{ print > ("out" gensub(/.*_/,"",1,$1)) }' 02052017_HHresults_sorted.tsv
or with any awk:
awk '{ n=$1; sub(/.*_/,"",n); print > ("out" n) }' 02052017_HHresults_sorted.tsv
No need to loop, use regex character class [..]:
awk 'match($1,/_([1-5])$/,a){ print >> a[1]".txt" }' 02052017_HHresults_sorted.tsv
I'm trying to do the following:
Check the cell for N/A or No; if it has either of these then it should output N/A or No
Check the cell for either £ or € or Yes; If it has one of these then it would continue to step 3. If it has $ then it should repeat the same input as the output.
Extract currency from cell using: REGEXEXTRACT(A1, "\$\d+") or REGEXEXTRACT(A1, "\£\d+") (I assume that's the best way)
Convert it to $ USD using GoogleFinance("CURRENCY:EURUSD") or GoogleFinance("CURRENCY:GBPUSD")
Output the original cell but replacing the extracted currency from step 3 with the output from step 4.
Examples: (Original --> Output)
N/A --> N/A
No --> No
Alt --> Alt
Yes --> Yes
Yes £10 --> Yes $12.19
Yes £10 per week --> Yes $12.19 per week
Yes €5 (Next) --> Yes $5.49 (Next)
Yes $5 22 EA --> Yes $5 22 EA
Yes £5 - £10 --> Yes $5.49 - $12.19
I am unable to get a working IF statement working, I could do this in normal code but can't work it out for spreadsheet formulas.
I've tried modifying #Rubén's answer lots of times to including the N/A as it's not the Sheets error, I also tried the same for making any USD inputs come out as USD (no changes) but I really can't get the hang of IF/OR/AND in Excel/Google Sheets.
=ArrayFormula(
SUBSTITUTE(
A1,
OR(IF(A1="No","No",REGEXEXTRACT(A1, "[\£|\€]\d+")),IF(A1="N/A","N/A",REGEXEXTRACT(A1, "[\£|\€]\d+"))),
IF(
A1="No",
"No",
TEXT(
REGEXEXTRACT(A1, "[\£|\€](\d+)")*
IF(
"€"=REGEXEXTRACT(A1, "([\£|\€])\d+"),
GoogleFinance("CURRENCY:EURUSD"),
GoogleFinance("CURRENCY:GBPUSD")
),
"$###,###"
)
)
)
)
The above, I tried to add an OR() before the first IF statement to try and include N/A as an option, in the below I tried it as you can see below in various different ways (replace line 4 with this)
IF(
OR(
A1="No",
"No",
REGEXEXTRACT(A1, "[\£|\€]\d+");
A1="No",
"No",
REGEXEXTRACT(A1, "[\£|\€]\d+")
)
)
But that doesn't work either. I thought using ; was a way to separate the OR expressions but apparently not.
Re: Rubén's latest code 16/10/2016
I've modified it to =ArrayFormula(
IF(NOT(ISBLANK(A2)),
IF(IFERROR(SEARCH("$",A2),0),A2,IF(A2="N/A","N/A",IF(A2="No","No",IF(A2="Alt","Alt",IF(A2="Yes","Yes",
SUBSTITUTE(
A2,
REGEXEXTRACT(A2, "[\£|\€]\d+"),
TEXT(
REGEXEXTRACT(A2, "[\£|\€](\d+)")
*
VLOOKUP(
REGEXEXTRACT(A2, "([\£|\€])\d+"),
{
{"£";"€"},
{GoogleFinance("CURRENCY:GBPUSD");GoogleFinance("CURRENCY:EURUSD")}
},
2,0),
"$###,###"
)
)
)))))
,"")
)
This fixes:
Blank cells no longer throw #N/A
Yes only cells no longer throw #N/A
Added another text value Alt
Changes the format of the currency to 0 decimal places rather than my original request of 2 decimal places.
As you can see in the image below the two red cells aren't quite correct as I never thought of this scenario, the second of the two values is staying in it's input form and not being converted to USD.
Direct answer
Try
=ArrayFormula(
IF(IFERROR(SEARCH("$",A1:A6),0),A1:A6,IF(A1:A6="N/A","N/A",IF(A1:A6="No","No",
SUBSTITUTE(
A1:A6,
REGEXEXTRACT(A1:A6, "[\£|\€]\d+"),
TEXT(
REGEXEXTRACT(A1:A6, "[\£|\€](\d+)")
*
VLOOKUP(
REGEXEXTRACT(A1:A6, "([\£|\€])\d+"),
{
{"£";"€"},
{GoogleFinance("CURRENCY:GBPUSD");GoogleFinance("CURRENCY:EURUSD")}
},
2,0),
"$###,###.00"
)
)
)))
)
Result
+---+------------------+---------------------+
| | A | B |
+---+------------------+---------------------+
| 1 | N/A | N/A |
| 2 | No | No |
| 3 | Yes £10 | Yes $12.19 |
| 4 | Yes £10 per week | Yes $12.19 per week |
| 5 | Yes €5 (Next) | Yes $5.49 (Next) |
+---+------------------+---------------------+
Explanation
OR function
Instead or using OR function, the above formula use nested IF functions.
REGEXTRACT
Instead of using a REGEXEXTRACT function for each currency symbol, a regex OR operator was used. Example
REGEXEXTRACT(A1:A6, "[\£|\€]\d+")
Three regular expressions were used,
get currency symbol and the amount [\£|\€]\d+
get the amount [\£|\€](\d+)
get the currency symbol [(\£|\€])\d+
Currency conversion
Instead of using nested IF to handle currency conversion rates, VLOOKUP and array is used. This could be make easier to maintain the formula assuming that more currencies could be added in the future.
I'm not very up on powershell and have a problem.
I have a powershell script that calls a batch file that mounts a backup image (shadowprotect), runs chkdsk against mounted image, dismounts image and returns.
All the output from the batch file processing is returned to my powershell script.
I'm trying to parse this to remove all the 'progress' lines that get generated by the chkdsk command, chkdsk doesn't seem to have any way to suppress this output (on large disk images I can end up with hundreds of progress lines).
I can create regular expression to catch all the 'Progress' lines and put them out to my log file, but I can't figure out the syntax that says to give me everything that does NOT match my regular expression.
Very short example of returned value I'm trying to parse:
Try to mount d:\backups\colt\F_VOL-b001-i453-cd.spi
Mounting image chain "D:\Backups\colt\F_VOL-b001.spf|D:\Backups\colt\F_VOL-b001-i014-cd-cw.spi|D:\Backups\colt\F_VOL-b001-i018-cd.spi|D:\Backups\colt\F_VOL-b001-i022-cd.spi|D:\Backups\colt\F_VOL-b001-i026-cd.spi|D:\Backups\colt\F_VOL-b001-i030-cd.spi|D:\Backups\colt\F_VOL-b001-i445-cd.spi|D:\Backups\colt\F_VOL-b001-i449-cd.spi|D:\Backups\colt\F_VOL-b001-i453-cd.spi"
The type of the file system is NTFS.
Volume label is Local Disk - single.
WARNING! F parameter not specified.
Running CHKDSK in read-only mode.
Stage 1: Examining basic file system structure ...
Progress: 0 of 4320 done; Stage: 0%; Total: 0%; ETA: 0:00:14
Progress: 0 of 4320 done; Stage: 0%; Total: 0%; ETA: 0:00:21 .
Progress: 6 of 4320 done; Stage: 0%; Total: 0%; ETA: 0:01:10 ..
Progress: 257 of 4320 done; Stage: 5%; Total: 2%; ETA: 0:01:47 ...
Progress: 769 of 4320 done; Stage: 17%; Total: 6%; ETA: 0:01:20
Progress: 2817 of 4320 done; Stage: 65%; Total: 19%; ETA: 0:00:23 .
Progress: 4320 of 4320 done; Stage: 100%; Total: 29%; ETA: 0:00:14 ..
4320 file records processed.
File verification completed.
Progress: 0 of 0 done; Stage: 99%; Total: 46%; ETA: 0:00:13 ...
0 large file records processed.
Progress: 0 of 0 done; Stage: 99%; Total: 46%; ETA: 0:00:13
0 bad file records processed.
Stage 2: Examining file name linkage ...
Progress: 4322 of 4360 done; Stage: 99%; Total: 92%; ETA: 0:00:01 .
Progress: 4340 of 4360 done; Stage: 99%; Total: 93%; ETA: 0:00:01 ..
Progress: 4344 of 4360 done; Stage: 99%; Total: 97%; ETA: 0:00:01 ...
Progress: 4360 of 4360 done; Stage: 100%; Total: 97%; ETA: 0:00:01
4360 index entries processed.
Index verification completed.
Progress: 0 of 0 done; Stage: 99%; Total: 97%; ETA: 0:00:01 .
0 unindexed files scanned.
Progress: 0 of 0 done; Stage: 99%; Total: 97%; ETA: 0:00:01 ..
0 unindexed files recovered.
Stage 3: Examining security descriptors ...
Security descriptor verification completed.
Progress: 0 of 0 done; Stage: 100%; Total: 99%; ETA: 0:00:00 ...
20 data files processed.
Windows has scanned the file system and found no problems.
No further action is required.
145500673 KB total disk space.
15814844 KB in 748 files.
180 KB in 22 indexes.
0 KB in bad sectors.
74721 KB in use by the system.
65536 KB occupied by the log file.
129610928 KB available on disk.
4096 bytes in each allocation unit.
36375168 total allocation units on disk.
32402732 allocation units available on disk.
OK - 0
Return value is 0
My script fragment looks like this:
# call batch file...
$Out = c:\batch\Mount_and_Chkdsk_image_file.cmd $NewFilePath
# append result of batch file to the log file, remove progress lines first...
$Out -replace ("^Progress:.*$", "")
Out-File -FilePath c:\batch\log\NewFileCheck.log -Append -InputObject $Out
In above attempt, since I can match the progress lines I thought I'd just replace them with nothing but no substitution happened.
(for testing I substituted the batch file call with just a file read of the raw unfiltered log file:
$FilePath = "c:\batch\test2.txt"
$Out = [System.Io.File]::ReadAllText($filePath)
)
Anyway, since replacement didn't work, I used google and tried understanding the select-string as an option since it takes regular expressions:
$Regex = 'Pattern:.*'
$Out | select-string -pattern $Regex -notmatch
This just puts out all the lines, nothing filtered out, I had hoped 'notmatch' would mean everything that didn't match. Didn't seem to matter how I varied regex I couldn't get that to do what I needed.
Tried many many more variations on the theme like:
#$Regex = '^((Progress:).*$)'
$Regex = '([?<!Progress:].*)'
$Out | Select-String -Pattern $Regex -AllMatches | %{$_.Matches } | %{$_.value}
But I'm obviously missing something. I would have thought there would be an easy function that if you could select a certain string you could also choose to not have that selection in the output.
Can anyone please help, how do I capture all the lines that aren't a match?
Regards,
Bryce S.
Sure, this can be done. By default when you load a text file with Get-Content it will load each line as a string, and the entire file will be an array of strings. You can run that through a Where statement and use the -notmatch operator to filter out things. Usage would be as such:
$ParsedData = Get-Content "c:\batch\test2.txt" | Where{$_ -notmatch "Progress:.*$"}
That would assist $ParsedData all of the lines in the file that did not match the regex "Progress:.*$".
Edit: Ok, what you're getting from your script is most likely a multi-line string. The easiest way that I know of is to simply break your string up on the new lines to make an array of strings. Something like this:
$Out.Split("`n") | Where{$_ -notmatch "Progress:.*$"}
$Out = $Out -replace ("^Progress:.*$", "")
Out-File -FilePath c:\batch\log\NewFileCheck.log -Append -InputObject $Out
The only problem you had was that -replace doesn't modify the left side value, it just returns the result, leaving $Out unchanged, so you have to make sure you assign the result back to $Out.
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'
};