0

我刚刚开始使用 Powershell,并且正在编写一些基本的脚本,从 foreach 和 if、elseif 构造开始。

我对 foreach 循环有疑问。

我试图用用户给出的参数编写一个简单的代码。我有一个包含 2 列的 CSV 文件:Zenskie(女性)和 Meskie(男性),其中填满了姓名。我的代码是在 CSV 中查找用户给出的名称,并作为输出提供有关性别的信息。

CSV 文件的一部分:

Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
Adelajda;Abelard
Adriana;Abraham
Adrianna;Achilles
Agata;Adam
Agnieszka;Adelard
Aida;Adnan
Bogna;Dawid

我还为我的妻子添加了一个小插曲 - 应该有一个专门针对她的名字的评论,在这里我有一个问题。结果是应该的,但它显示了多次(我猜与 CSV 中的行一样多)。

如果用户给出的输入不在列表中,我还尝试在最后添加一个“else”部分。但是当我这样做时,它会给出之前“elseif”的结果。

我尝试将另一个 elseif 与“elseif ($UserName -ne $Man) 一起使用,但它也给了我错误的答案。

我敢打赌我在这里遗漏了一些简单的东西......


Param (
  [string]$UserName = (Read-Host " Tell me your name ")
)

$Names = Import-Csv -Path C:\Powershell\Moje_nowe\Lista_imion3.csv -Delimiter ";"

ForEach ($item in $Names) {
  $Women = $item.("Zenskie")
  $Man = $item.("Meskie")
  if ($UserName -eq $Women) {
    Write-Output "$UserName you are women!"
  }
  elseif ($UserName -eq $Man) {
    Write-Output "$UserName you are man!"
  }
  elseif ($UserName -eq "Bogna") {
    Write-Output "Kiss me!! :)"
  }
  else {
    Write-Output "$UserName you have an odd name"
  }
}

预期结果:

对于输入博尼亚:

Tell me your name: bogna

Kiss me!! :)

实际结果:

Kiss me!! :)

Kiss me!! :)

Kiss me!! :)

等等

当我在输入不在列表中时添加部分时:

预期的:

Tell me your name: bdsdsd


bdsdsd you have an odd name

实际的:

无论我输入什么

bdsdsd you have an odd name

bdsdsd you have an odd name

bdsdsd you have an odd name

等等

4

3 回答 3

1

您可以使用“do ... until”循环来保持游戏运行... ;-)

$CSV = @'
Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
Adelajda;Abelard
Adriana;Abraham
Adrianna;Achilles
Agata;Adam
Agnieszka;Adelard
Aida;Adnan
Bogna;Dawid
'@ | ConvertFrom-Csv -Delimiter ';'

do {
    $UserName = Read-Host " Tell me your name (End with 'quit')" 
    if ($UserName -eq 'Bogna') { "Kiss me!! :)" }
    elseif ($UserName -in $CSV.Zenskie) { "$UserName you are woman!" }
    elseif ($UserName -in $CSV.Meskie) { "$UserName you are man!" }
    else  { "$UserName you have an odd name" }
} until ($Username -eq 'quit')
于 2019-09-28T00:17:26.063 回答
1

结果是应该的,但它显示了多次(我猜与 CSV 中的行一样多)。

确实:鉴于您分别遍历从 CSV 行导入的对象,该if语句会针对每个.

break一旦在ifandelseif分支中找到匹配项以修复该问题(但不在else分支中,因为它必须潜在地等待所有对象被检查以推断未找到匹配项),请使用退出循环。

警告breakforeach 循环(语句)中使用(如您的问题),而不是在带有cmdlet的管道ForEach-Object 中(如在接受的答案中)。在后一种情况下,在调用堆栈上break查找封闭循环,如果没有找到,则整个退出脚本
简而言之:只在循环( , , ...) 或语句breakcontinueforeachwhileswitch中使用and break并且continue与管道完全无关(但您可以returnForEach-Object脚本块中使用以跳到下一个管道输入对象)。

从 PowerShell v7 开始,没有直接支持按需中断(退出)管道;在此 GitHub 问题中要求添加此类支持。

但是,利用-inPowerShell 的数组成员资格测试(包含)运算符(PSv3+;在 PSv2 中,或者-contains在操作数顺序相反的地方使用)更简单、更有效,它允许您执行单个测试(每个比较值)跨所有 CSV 行,如Olaf 的有用答案所示。

一个简化的例子:

注意:下面的代码首先将所有 CSV 数据读入内存,然后从中创建两个数组,分别存储两列中的值。对于具有名字列表的文件,这不应该是内存问题;但是,在处理大型输入数据集时,您可能需要一种在管道中逐行处理输入 CSV 文件的解决方案。

# Parse sample CSV input into objects with .Zenskie and .Meskie properties.
$names = @'
Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
'@ | ConvertFrom-Csv -Delimiter ';'

# Extract the male and female names into individual arrays.
# Note how no quoting is needed to acces the properties (columns) by names
# and how accessing a property on the input array ($names) automatically
# returns the property values *from all array elements*, a feature known
# as member enumeration.
$maleNames = $names.Meskie
$femaleNames = $names.Zenskie

# Test a few sample names.
'Abdon', 'Bogna', 'Adela', 'Bill' | ForEach-Object {

  if ($_ -eq 'Bogna') { # exception
    "Pocałuj mnie!! :)"
  }
  elseif ($_ -in $maleNames) { # -in tests presence in the array, case-insensitively
    "$_, you are a man."
  }
  elseif ($_ -in $femaleNames) {    
    "$_, you are a woman."
  }
  else {
    "$_, you have an odd name."
  }

}

以上产生:

Abdon, you have are a man.
Pocałuj mnie!! :)
Adela, you have are a woman.
Bill, you have an odd name.
于 2019-09-28T16:47:33.947 回答
-1

试试这个 :

Param ([string]$UserName = (Read-Host " Tell me your name " ))

#if Bogna, not necessary to loop, print and out
if ($UserName -eq "Bogna")
{
   "Kiss me!! :)  (nice declaration)"
   return
}

#loop on all elements and if you found as you want, break for not continue ==> attention break leave the programm in pipe foreach
$FirstElement=Import-csv -Path "C:\Powershell\Moje_nowe\Lista_imion3.csv" -Delimiter ";" | %{

    if ($_.Zenskie -eq $UserName)
    {
        "$UserName you are women!"

        break
    }
    elseif ($_.Meskie -eq $UserName)
    {
        "$UserName you are man!"

        break
    }

}

# BE CAREFULL IF BREAK IS RAISED THE SCRIPT IS ENDED AND THIS CODE DOESNT EXECUTED
if (! $FirstElement)
{
"$UserName you have an odd name, Brrrrr !"
}

如果您的脚本在 csv 循环后继续,请不要让脚本中断,您可以这样做:

Param ([string]$UserName = (Read-Host " Tell me your name " ))

#if Bogna, not necessary to loop, print and out
if ($UserName -eq "Bogna")
{
   "Kiss me!! :)  (nice declaration)"
   return
}

#loop on all elements and if you found as you want, break for not continue
$FirstElement=$null

$allElement=Import-csv -Path "C:\Powershell\Moje_nowe\Lista_imion3.csv" -Delimiter ";"

foreach ($item in $allElement)
{
     if ($item.Zenskie -eq $UserName)
    {
        "$UserName you are women!"
        $FirstElement=$item
        break
    }
    elseif ($item.Meskie -eq $UserName)
    {
        "$UserName you are man!"
        $FirstElement=$item
        break
    }
}

#if not element founded
if (! $FirstElement)
{
    "$UserName you have an odd name, Brrrrr !"
}
于 2019-09-28T05:54:55.490 回答