我有一个文本文件,在文本文件中有两个名称,完全像这样。
汤姆·哈迪
布拉德·皮特
我用它来从文件中提取名称并分割它们。
$Names = gc C:\Temp\Name.txt
ForEach-Object {-Split $Names}
然后如何将每个名字分配给$ FirstName和每个姓氏给$ LastName?
其背后的想法是,在每一行中,我将为每个$ FirstName使用每个名称创建一个特定的单独项目。
我了解到,执行上述操作后,名称的每个部分都分配给$ _,因此我可以对每个部分执行相同的操作,即
$Names = gc C:\Temp\Name.txt
$SplitNames = ForEach-Object {-Split $Names}
ForEach ($_ in $SplitNames) {Write-Host 'Name is' $_}
Name is Tom
Name is Hardy
Name is Brad
Name is Pitt
希望这是有道理的,如果需要更多说明,请告诉我。
答案 0 :(得分:5)
# Read the input file line by line with Get-Content and send each line
# to the ForEach-Object cmdlet, which sees each line as automatic variable
# $_
Get-Content C:\Temp\Name.txt | ForEach-Object {
# Split the line into tokens by whitespace.
# * $firstName receives the 1st token,
# * $lastName the 2nd one (if there were more, $lastName would become an *array*)
$firstName, $lastName = -split $_
# Work with $firstName and $lastName
}
如果您想收集名称对以备后用,请考虑将其包装在自定义对象中,如DarkLite1's answer所示。
关于您尝试过的事情:
ForEach-Object { -Split $Names }
ForEach ($_ in $SplitNames) {Write-Host 'Name is' $_}
如果在未提供流水线输入的情况下调用ForEach-Object
,则脚本块将被执行一次 ,因此ForEach-Object { -Split $Names }
实际上与仅调用{{1} }。
通常,这些陈述表明,在 PowerShell枚举构造之间的区别上存在困惑:
-Split $Names
)|
$_
1, 2, 3 | ForEach-Object { "number: $_ " }
,以免引起混淆)$_
PSv4 + 还提供了 .ForEach()
method :
foreach ($num in 1, 2, 3) { "number: $num" }
循环,它旨在枚举内存中的集合 ,但是您 invoke it as a method集合本身。 foreach
cmdlet,它是自动变量ForEach-Object
,它反映了当前迭代的对象。$_
也许令人困惑,(1, 2, 3).ForEach({ "number: $_" }
还是foreach
的内置别名。如果使用ForEach-Object
,则上下文将确定所使用的构造:在管道(命令上下文,参数模式)中,foreach
引用foreach
cmdlet,否则引用ForEach-Object
循环(表示模式)。 [1]
关于何时使用哪种构造:在以下之间需要权衡:
foreach
循环通常最快,其次是foreach
方法,其中.ForEach()
cmdlet最慢(管道通常很慢) [2] < / sup> ForEach-Object
cmdlet(管道)提供流处理,其中每个对象在生成时都进行处理;除非整体结果收集在内存中(例如,与输出到文件相反),否则此 keeps内存将使用常量,而不管最终要处理多少个对象。ForEach-Object
和foreach
要求输入集合必须完整存在于内存中 。.ForEach()
cmdlet(通常是管道)在处理/生产对象时将其传递给对象,因此通常您会立即开始看到输出。ForEach-Object
和foreach
,在给出命令的输出时,必须在开始枚举之前先完整地收集该命令的输出。.ForEach()
方法可以按原样用作表达式的一部分,而.ForEach()
的使用要求将ForEach-Object
括起来并使用{{ 1}}循环需要包含(...)
foreach
方法提供了允许简洁表达的附加功能(可以使用$(...)
和.ForEach()
来模拟该功能,但更冗长) [1]通过运行Get-Help about_Parsing
,您可以详细了解PowerShell的两种基本解析模式,即参数模式(类似于命令)和表达式模式。 / p>
[2]运行以下使用微不足道的循环主体的性能比较命令,显示foreach
在测试中比ForEach-Object
快,而foreach
则最慢。您可以从this Gist下载.ForEach()
脚本:
ForEach-Object
在笔记本电脑上运行Windows PowerShell v5.1 / PowerShell Core 6.1.0-preview.4的单核Windows 10 VM的结果;请注意,绝对数字并不重要,并且会根据许多变量而有所不同,但是 ratio (列Test-Command.ps1
)应该会给您一个感觉。
如果您获得不同的排名,请告诉我们。
Windows PowerShell v5.1:
100个项目,平均运行10,000次:
# 100 items, average of 10,000 runs
$a=1..100; ./Time-Command { foreach($e in $a) { ++$e } }, { $a.ForEach({ ++$_ }) }, { $a | ForEach-Object { ++$_ } } 10000
# 1 million items, average of 10 runs
$a=1..1e6; ./Time-Command { foreach($e in $a) { ++$e } }, { $a.ForEach({ ++$_ }) }, { $a | ForEach-Object { ++$_ } } 10
1百万个项目,平均10次运行:
Factor
PowerShell Core 6.1.0-preview.4:
100个项目,平均运行10,000次:
Command FriendlySecs (10000-run avg.) TimeSpan Factor
------- ----------------------------- -------- ------
foreach($e in $a) { ++$e } 0.000 00:00:00.0001415 1.00
$a.ForEach({ ++$_ }) 0.000 00:00:00.0002937 2.08
$a | ForEach-Object { ++$_ } 0.001 00:00:00.0006257 4.42
1百万个项目,平均10次运行:
Command FriendlySecs (10-run avg.) TimeSpan Factor
------- -------------------------- -------- ------
foreach($e in $a) { ++$e } 1.297 00:00:01.2969321 1.00
$a.ForEach({ ++$_ }) 2.548 00:00:02.5480889 1.96
$a | ForEach-Object { ++$_ } 5.992 00:00:05.9917937 4.62
一般观察:
在100个项目和100万个项目之间的相对性能变化不大:Command FriendlySecs (10000-run avg.) TimeSpan Factor
------- ----------------------------- -------- ------
foreach($e in $a) { ++$e } 0.000 00:00:00.0001981 1.00
$a.ForEach({ ++$_ }) 0.000 00:00:00.0004406 2.22
$a | ForEach-Object { ++$_ } 0.001 00:00:00.0008829 4.46
大约是Command FriendlySecs (10-run avg.) TimeSpan Factor
------- -------------------------- -------- ------
foreach($e in $a) { ++$e } 1.741 00:00:01.7412378 1.00
$a.ForEach({ ++$_ }) 4.099 00:00:04.0987548 2.35
$a | ForEach-Object { ++$_ } 8.119 00:00:08.1188042 4.66
的2倍和4-5倍比foreach
快。
在这些测试中,Windows PowerShell明显比PS Core快,而macOS和Linux上的PS Core似乎更慢。
答案 1 :(得分:3)
Split
会在拆分每个位置后为您提供一个包含内容的数组。
您可以寻址数组中的每个条目,然后用于其他目的:
例如:("Tom Hardy" -split " ")[0]
= Tom
$Names = gc C:\Temp\Name.txt
foreach ($name in $Names)
{
$cutted = $name.Split()
$firstname = $cutted[0]
$lastname = $cutted[1]
#Do whatever you need to do with the names here
}
如@iRon所述,您实际上可以跳过一个步骤,并将其直接从拆分中保存到两个变量中:
$Names = gc C:\Temp\Name.txt
foreach ($name in $Names)
{
$firstname, $lastname = $name -split " "
#Do whatever you need to do with the names here
}
或者作为一个单行:
Get-Content -Path "C:\Temp\Name.txt" | % {$firstname, $lastname = $_ -split " "; #Do something with the variables}
答案 2 :(得分:3)
与@Paxz相同,但有一些解释和建议:
$Names = @(
'Brad Pitt',
'Tom Hardy',
'Daniel Craig Junior'
)
# the .ForEAch method is used as it's faster then piping data to Foreach-Object
$result = $Names.ForEach({
# we use the second argument of -Split to indicate
# we're only interested in two values
$tmpSplit = $_ -split ' ', 2
# we then create an object that allows us to
# name things propertly so we can play with it later withoout hassle
[PSCustomObject]@{
Input = $_
FirstName = $tmpSplit[0]
LastName = $tmpSplit[1]
}
})
# here we show the result of all our objects created
$result
# enable verbose text to he displayed
$VerbosePreference = 'Continue'
$result.ForEach({
# here we can easily address the object by its property names
Write-Verbose "Input '$($_.Input)' FirstName '$($_.FirstName)' LastName '$($_.LastName)'"
})
# disable verbose messages, because we don't need this in production
$VerbosePreference = 'SilentlyContinue'