使用foreach循环执行powershell脚本后的结果过多
我刚刚开始我的Powershell之旅,我正在做一些基本的脚本编写,从foreach和if,elseif结构开始 我对foreach循环有问题 我试图用用户给定的参数编写一个简单的代码。我有一个CSV文件,有两列:Zenskie(女性)和Meskie(男性)填写了姓名。我的代码是在CSV中查找用户提供的姓名,并作为输出提供有关性别的信息 CSV文件的一部分:使用foreach循环执行powershell脚本后的结果过多,powershell,loops,Powershell,Loops,我刚刚开始我的Powershell之旅,我正在做一些基本的脚本编写,从foreach和if,elseif结构开始 我对foreach循环有问题 我试图用用户给定的参数编写一个简单的代码。我有一个CSV文件,有两列:Zenskie(女性)和Meskie(男性)填写了姓名。我的代码是在CSV中查找用户提供的姓名,并作为输出提供有关性别的信息 CSV文件的一部分: Zenskie;Meskie Ada;Aaron Adamina;Abdon Adela;Abel Adelajda;Abelard Ad
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=(读主机“告诉我你的名字”)
)
$Names=导入Csv-路径C:\Powershell\Moje\u nowe\Lista\u imion3.Csv-分隔符”;"
ForEach($名称中的项目){
$Women=$item.(“Zenskie”)
$Man=$item.(“梅斯基”)
如果($UserName-eq$Women){
写入输出“$UserName您是女性!”
}
elseif($UserName-eq$Man){
写入输出“$UserName您就是男人!”
}
elseif($UserName-eq“Bogna”){
编写输出“吻我!!:)”
}
否则{
写入输出“$UserName您有一个奇数名称”
}
}
预期结果: 对于输入Bogna:
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
依此类推,你可以用“do…”。。。直到“循环以保持游戏运行…;-)
试试这个:
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循环后继续,请不要将脚本保留为break,您可以执行以下操作:
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 !"
}
结果是应该的,但它显示了多次(我猜是CSV中的行数)
事实上:假设您分别循环从CSV行导入的对象,则会对每个行计算if
语句
在if
和elseif
分支中找到匹配项后,使用break
退出循环,以修复该问题(但不能在else
分支中,因为它必须等待检查所有对象,以推断未找到匹配项)
注意事项:仅在foreach
循环(语句)(如您的问题所示)中使用break
,而不是在管道中使用foreach对象
cmdlet(如中)。在后一种情况下,break
在调用堆栈上查找封闭循环,如果没有找到,则作为一个整体退出脚本。简而言之:只在循环(
foreach
,while
,…)或switch
语句中使用break
和continue
与管道完全无关(但您可以在ForEach对象
脚本块中使用return
,跳到下一个管道输入对象)
从PowerShell v7开始,对于按需中断(退出)管道没有直接支持;中正在请求添加此类支持
但是,利用PowerShell的数组成员资格测试(包含)操作符(PSv3+;在PSv2中,或者在操作数顺序相反的情况下使用-contains
)更简单、更有效,它允许您执行单个测试(每个比较值)跨所有CSV行,如中所示
一个简化的例子:
注意:下面的代码首先将所有CSV数据读取到内存中,然后从中为两列中的值创建两个数组。对于具有名字列表的文件,这不应该是内存问题;但是,在处理大型输入数据集时,您可能需要在管道中逐行处理输入CSV文件的解决方案
上述收益率:
Abdon,你是个男人。
Pocałuj mnie!!:)
阿德拉,你是个女人。
比尔,你的名字很奇怪。
break
是一个错误的命令,因为在没有封闭循环的情况下,它作为一个整体退出脚本;break
不能用于退出管道-除非在管道周围使用break
虚拟循环,否则目前无法提前退出管道-请参阅。简而言之:您的代码碰巧是可行的,但这只是因为在这种情况下循环后不需要运行代码;如果有其他代码要运行,它就不会运行。我仍然+1您的建议,即使它在大文件上会产生反作用。您遍历所有行2次,并将所有内容存储在内存中,对于要测试的每个名称,您可能会测试所有人和潜力所有女性都可以找到你的解决方案,而不是浏览一次csv列表并测试每行的所有姓名(一般来说,你正在寻找的内容数量远低于你在计算机科学中搜索的内容,尤其是csv)@esperento 57:感谢您更新您的答案;重新设计决策:我同意这是不幸的,但问题是现在更改行为可能会破坏现有代码。re大文件:是的,但我们正在处理一个名字列表,它不太可能太大而无法放入内存或需要很长时间才能加载;不过,我添加了一个注释答案是肯定的。
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 !"
}
# 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."
}
}