在for循环中循环访问多个变量

时间:2018-07-13 11:08:42

标签: powershell variables for-loop

我刚开始使用Powershell,这是我的第一个脚本。

我正在检查日志文件的后50行中的3个字符串。我需要找到所有三个字符串,如果缺少其中任何一个,则会显示错误消息。我已经编写了以下脚本,但它没有给我预期的结果。

(Get-Content C:\foo\bar.log )[-1..-50] | Out-File C:\boom\shiva\log.txt
$PO1 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P01_RCV> ok"}
$PO2 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P02_SND> ok"}
$PO3 = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P03_RCV> ok"}

我对以上代码感到满意。问题出在下面。我不想使用if-else三次。我正在努力起草一个for循环,该循环可以节省空间,但仍然给我相同的结果。

if (!$PO1)
{
    "PO1 is critical"
}
else
{
    "PO1 is OK"
}
if (!$PO2)
{
    "PO2 is critical"
}
else
{
    "PO2 is OK"
}
if (!$PO3)
{
    "PO3 is critical"
}
else
{
    "PO3 is OK"
}

有人可以给我一个小例子,说明我如何将这3个if-else放入一个for循环中。

4 个答案:

答案 0 :(得分:4)

如果您只想找出所有3个字符串都存在,则此脚本还将显示缺少的三个字符串。
(二进制编码在变量$ Cnt中)

## Q:\Test\2018\07\13\SO_51323760.ps1
##
$Last50 = Get-Content 'C:\foo\bar.log' | Select-Object -Last 50
$Cnt = 0

if ($Last50 -match "<Ping:AD_P01_RCV> ok"){$Cnt++}
if ($Last50 -match "<Ping:AD_P02_SND> ok"){$Cnt+=2}
if ($Last50 -match "<Ping:AD_P03_RCV> ok"){$Cnt+=4}

if ($cnt -eq 7){
   "did find all 3 strings "
} else {
   "didn't find all 3 strings ({0})" -f $cnt
}

Variant立即抱怨缺少P0(1..3)

$Last50 = Get-Content 'C:\foo\bar.log' | Select-Object -Last 50

if (!($Last50 -match "<Ping:AD_P01_RCV> ok")) {"PO1 is critical"}
if (!($Last50 -match "<Ping:AD_P02_SND> ok")) {"PO2 is critical"}
if (!($Last50 -match "<Ping:AD_P03_RCV> ok")) {"PO3 is critical"}

抱歉,这个星期一我有点慢。

要通过构建变量名称在循环中检查不同的变量,请执行以下操作:

1..3| ForEach-Object {
  If (!(Get-Variable -name "P0$_").Value){"`$P0$_ is critical"}
}

答案 1 :(得分:1)

使用哈希表比使用单独命名的变量可以更好地解决您要执行的操作。

Sub Parent_sub()
Dim v1 As Integer,v2 As Integer,v3 as Integer

v1 = 0
v2 = -1
v3 = -2
  Child_sub v1, v2, v3
msgbox "the variables are " & v1 & " ," & v2 & ", and " & v3
End Sub

Sub Child_sub(ByRef c1 as Integer, ByRef c2 as Integer, ByRef c3 as 
Integer)

c1 = 3
c2 = 4
c3 = 5

End Sub

您可以检查所有行是否至少出现一次,如下所示:

$data = Get-Content 'C:\boom\shiva\log.txt'

$ht = @{}
1..3 | ForEach-Object {
    $key = 'P{0:d2}' -f $_
    $str = if ($_ -eq 2) {"${key}_SND"} else {"${key}_RCV"}
    $ht[$key] = $data -match "<ing:AD_${str}> ok"
}

$ht.Keys | ForEach-Object {
    if ($ht[$_]) {
        "${key} found in log."
    } else {
        "${key} not found in log."
    }
}

答案 2 :(得分:0)

PSv3在-Tail中引入了-LastGet-Content)参数,这是从 end 中提取固定行数的最有效方法一个文件。

您可以将其输出通过管道传递到Select-String,后者接受正则表达式模式的数组,其中任何一个都会产生匹配项(隐式OR逻辑)。

$matchingLines = Get-Content -Tail 50 C:\foo\bar.log |
  Select-String '<Ping:AD_P01_RCV> ok', '<Ping:AD_P02_SND> ok', '<Ping:AD_P03_RCV> ok'

if ($matchingLines) { # at least 1 of the regexes matched
   $matchingLines.Line  # output the matching lines
} else {  # nothing matched
  Write-Warning "Nothing matched."
}

答案 3 :(得分:0)

我终于得到了草稿,该草稿解决了我的查询以通过for循环循环变量。最后,我不得不将这些单独的变量转换为数组。但是,htis给了我预期的结果。基本上,我需要此脚本来向Nagios插件提供输入,该插件需要进行少量修改但已完成。

(Get-Content C:\foo\bar.log )[-1..-50] | Out-File C:\boom\shiva\log.txt
$j = 1
$PO = new-object object[] 3
$PO[0] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P01_RCV> ok"}
$PO[1] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P02_SND> ok"}
$PO[2] = Get-Content C:\boom\shiva\log.txt | where {$_ -match "<Ping:AD_P03_RCV> ok"}
foreach( $i in $PO){
    if (!$i){
        "PO "+$j+" is CRITICAL"}
    else{
        "PO "+$j+" is OK"}
    $j+=1
}

感谢LotPings,Ansgar和mklement0的支持和回应。我从你的答案中得到了一些东西。