拆分一个字符串,然后分配拆分
Split a String and then assign the splits
我有一个文本文件,文本文件中有两个名字,就像这样。
Tom Hardy
Brad Pitt
我用它来从文件中提取名称并拆分它们。
$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
希望这是有道理的,如果需要更多说明,请告诉我。
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所说,其实可以跳过一步,直接从split中保存到两个变量中:
$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}
与@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'
# 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
}
如果您想收集名称对供以后使用,请考虑将它们包装在自定义对象中,如 。
至于你试过的:
ForEach-Object { -Split $Names }
ForEach ($_ in $SplitNames) {Write-Host 'Name is' $_}
如果您调用 ForEach-Object
而不向其提供管道输入,脚本块将执行 一次,因此 ForEach-Object { -Split $Names }
实际上与刚才相同呼叫 -Split $Names
.
通常,这些陈述表明 PowerShell 的各种枚举结构之间的区别存在混淆。
PowerShell 的各种枚举构造:
-
- 旨在通过 管道 (
|
) 接收 输入
- 反映每个输入对象在自动变量
$_
- 例如,
1, 2, 3 | ForEach-Object { "number: $_ " }
- 注意:发送
$null
作为输入 会 导致调用 - 不同于 foreach
循环 .
-
- 旨在枚举一个指定的内存集合
- 通过一个自己选择的迭代变量(最好不要选择
$_
,以免混淆)
- 例如,
foreach ($num in 1, 2, 3) { "number: $num" }
- 注意:
$null
因为输入集合 而不是 导致进入循环体 - 不像 ForEach-Object
.
PSv4+ 还提供 .ForEach()
array method:
- 类似于
foreach
循环,它被设计为枚举一个内存中的集合,但是你invoke it as a method 在集合本身上。
- 类似于
ForEach-Object
cmdlet,它是自动变量$_
反映当前迭代的对象。
- 它提供额外的功能,例如按名称枚举属性、执行类型转换、调用方法。
- 例如,
(1, 2, 3).ForEach({ "number: $_" }
- 注意:
$null
因为输入集合 而不是 导致调用脚本块 - 与 ForEach-Object
不同。
也许令人惊讶的是,PowerShell 的 switch
statement 也对碰巧是集合的输入执行枚举。
-
foreach ($num in 1, 2, 3) { "number: $num" }
的 switch
等价于(注意使用自动变量 $_
作为隐式迭代器变量):
switch (1, 2, 3) { default { "number: $_"; continue } }
switch
在内存效率、性能和输出时序上与foreach
循环语句类似,下面不再单独讨论。它的优点是能够使用复杂的条件以及能够使用 -File
选项直接枚举文件的行。
- 注意:
$null
作为输入集合 确实 导致对分支的评估 - 与 foreach
循环不同。
有点令人困惑,foreach
也是ForEach-Object
的内置别名。如果你使用foreach
,它是决定使用哪个构造的解析上下文:在管道(命令上下文,参数模式)中,foreach
指的是 ForEach-Object
cmdlet,否则它指的是 foreach
loop(表达式模式)- 详见。
权衡:什么时候使用什么构造:
注意:以下重点介绍类似循环的结构,但通常适用与对比使用管道中的 cmdlet(流) 一方面,与 语言语句 和 基于运算符的表达式/方法调用 另一方面[1]
- 性能(执行速度)
foreach
循环通常最快,其次是 .ForEach()
方法,ForEach-Object
cmdlet 最慢(管道通常很慢;请参阅底部)
- 内存效率
- 只有
ForEach-Object
cmdlet(管道)提供 streaming 处理,其中每个对象在生成时被处理;除非将总体结果收集在内存中(例如,与输出到文件相反),这 保持内存使用不变 ,无论最终处理了多少对象。
foreach
和 .ForEach()
要求输入集合在内存中 完整 .
- 输出时序
ForEach-Object
cmdlet(以及一般的管道)在处理/生成对象时传递对象,因此您通常会立即开始看到输出。
foreach
和 .ForEach()
,当直接对命令进行操作时,必须先完整地收集该命令的输出,然后才能开始枚举。
- 语法便利性和功能集
.ForEach()
方法可以 原样 作为表达式的一部分使用,而 ForEach-Object
的使用需要包含 (...)
和使用 foreach
循环需要包含 $(...)
.ForEach()
方法提供了允许简洁表达式的附加功能(可以模拟 foreach
和 ForEach-Object
的功能,但更冗长)
性能比较:
运行 以下 性能比较命令 ,它使用了一个简单的循环体,显示 foreach
比 .ForEach()
快正如预期的那样,我的测试中 ForEach-Object
最慢。请注意,代码从 this Gist 下载并定义 Time-Command
函数(我可以向你保证这样做是安全的,但你应该始终自己检查源代码):
# Download and define the Time-Command function.
irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
Write-Verbose -vb "1,000 items, average of 10 runs"
$a=1..1000; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
Write-Verbose -vb "100,000 items, average of 10 runs"
$a=1..1e5; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
双核 Windows 10 虚拟机的结果,Windows PowerShell v5.1 / PowerShell Core 7.2.0-preview.6;请注意,绝对数字并不重要,会因许多变量而异,但 比率 (第 Factor
列)应该能让您有所了解。
Windows PowerShell v5.1:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013639
3.99 0.005 $a.ForEach({ (++$_) }) 00:00:00.0054464
7.46 0.010 $a | ForEach-Object { (++$_) } 00:00:00.0101785
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.014 foreach($e in $a) { (++$e) } 00:00:00.0144434
37.56 0.542 $a.ForEach({ (++$_) }) 00:00:00.5424872
62.61 0.904 $a | ForEach-Object { (++$_) } 00:00:00.9043278
PowerShell Core 7.2.0-preview.6:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013071
4.23 0.006 $a.ForEach({ (++$_) }) 00:00:00.0055324
8.04 0.011 $a | ForEach-Object { (++$_) } 00:00:00.0105058
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.010 foreach($e in $a) { (++$e) } 00:00:00.0095252
34.12 0.325 $a.ForEach({ (++$_) }) 00:00:00.3250133
57.83 0.551 $a | ForEach-Object { (++$_) } 00:00:00.5508560
注意:在发现原始方法中的缺陷后,已更新上述基准。新的数字导致不同的结论。
一般观察:
foreach
是迄今为止最快的,其次是 .ForEach()
,ForEach-Object
是迄今为止最慢的
- 注意:虽然这是预期的,但考虑到管道引入了开销,减速在很大程度上归因于低效的实现
ForEach-Object
(和 Where-Object
)从 PowerShell 7.2 开始的 cmdlet - 请参阅 this blog post for an excellent analysis, which led to GitHub feature request #10982.
foreach
的性能优势随着迭代次数的增加而增长,与大数相当可观。然而,与迭代次数无关,.ForEach()
似乎是 ForEach-Object
.
的两倍左右
就绝对计时而言,PowerShell Core 似乎比 Windows 具有较大迭代次数的 PowerShell 表现更好。
在 macOS 上(上面未显示结果),减速因素似乎更大,而且执行速度似乎也从绝对值来看更慢。
Re-运行 同一 PowerShell 会话中的测试扩大了性能差距,表明只有 foreach
语句受益于按需编译。
[1] 例如,对比使用 cmdlet Get-Content
vs. with language statement switch
-File
; or contrasting filtering a collection with cmdlet Where-Object
vs. via method .Where()
or operator -match
.
读取文件
我有一个文本文件,文本文件中有两个名字,就像这样。
Tom Hardy
Brad Pitt
我用它来从文件中提取名称并拆分它们。
$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
希望这是有道理的,如果需要更多说明,请告诉我。
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所说,其实可以跳过一步,直接从split中保存到两个变量中:
$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}
与@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'
# 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
}
如果您想收集名称对供以后使用,请考虑将它们包装在自定义对象中,如
至于你试过的:
ForEach-Object { -Split $Names }
ForEach ($_ in $SplitNames) {Write-Host 'Name is' $_}
如果您调用 ForEach-Object
而不向其提供管道输入,脚本块将执行 一次,因此 ForEach-Object { -Split $Names }
实际上与刚才相同呼叫 -Split $Names
.
通常,这些陈述表明 PowerShell 的各种枚举结构之间的区别存在混淆。
PowerShell 的各种枚举构造:
-
- 旨在通过 管道 (
|
) 接收 输入
- 反映每个输入对象在自动变量
$_
- 例如,
1, 2, 3 | ForEach-Object { "number: $_ " }
- 注意:发送
$null
作为输入 会 导致调用 - 不同于foreach
循环 .
- 旨在通过 管道 (
-
- 旨在枚举一个指定的内存集合
- 通过一个自己选择的迭代变量(最好不要选择
$_
,以免混淆) - 例如,
foreach ($num in 1, 2, 3) { "number: $num" }
- 注意:
$null
因为输入集合 而不是 导致进入循环体 - 不像ForEach-Object
.
PSv4+ 还提供
.ForEach()
array method:- 类似于
foreach
循环,它被设计为枚举一个内存中的集合,但是你invoke it as a method 在集合本身上。 - 类似于
ForEach-Object
cmdlet,它是自动变量$_
反映当前迭代的对象。 - 它提供额外的功能,例如按名称枚举属性、执行类型转换、调用方法。
- 例如,
(1, 2, 3).ForEach({ "number: $_" }
- 注意:
$null
因为输入集合 而不是 导致调用脚本块 - 与ForEach-Object
不同。
- 类似于
也许令人惊讶的是,PowerShell 的
switch
statement 也对碰巧是集合的输入执行枚举。-
foreach ($num in 1, 2, 3) { "number: $num" }
的switch
等价于(注意使用自动变量$_
作为隐式迭代器变量):
switch (1, 2, 3) { default { "number: $_"; continue } }
switch
在内存效率、性能和输出时序上与foreach
循环语句类似,下面不再单独讨论。它的优点是能够使用复杂的条件以及能够使用-File
选项直接枚举文件的行。- 注意:
$null
作为输入集合 确实 导致对分支的评估 - 与foreach
循环不同。
-
有点令人困惑,foreach
也是ForEach-Object
的内置别名。如果你使用foreach
,它是决定使用哪个构造的解析上下文:在管道(命令上下文,参数模式)中,foreach
指的是 ForEach-Object
cmdlet,否则它指的是 foreach
loop(表达式模式)- 详见
权衡:什么时候使用什么构造:
注意:以下重点介绍类似循环的结构,但通常适用与对比使用管道中的 cmdlet(流) 一方面,与 语言语句 和 基于运算符的表达式/方法调用 另一方面[1]
- 性能(执行速度)
foreach
循环通常最快,其次是.ForEach()
方法,ForEach-Object
cmdlet 最慢(管道通常很慢;请参阅底部)
- 内存效率
- 只有
ForEach-Object
cmdlet(管道)提供 streaming 处理,其中每个对象在生成时被处理;除非将总体结果收集在内存中(例如,与输出到文件相反),这 保持内存使用不变 ,无论最终处理了多少对象。 foreach
和.ForEach()
要求输入集合在内存中 完整 .
- 只有
- 输出时序
ForEach-Object
cmdlet(以及一般的管道)在处理/生成对象时传递对象,因此您通常会立即开始看到输出。foreach
和.ForEach()
,当直接对命令进行操作时,必须先完整地收集该命令的输出,然后才能开始枚举。
- 语法便利性和功能集
.ForEach()
方法可以 原样 作为表达式的一部分使用,而ForEach-Object
的使用需要包含(...)
和使用foreach
循环需要包含$(...)
.ForEach()
方法提供了允许简洁表达式的附加功能(可以模拟foreach
和ForEach-Object
的功能,但更冗长)
性能比较:
运行 以下 性能比较命令 ,它使用了一个简单的循环体,显示 foreach
比 .ForEach()
快正如预期的那样,我的测试中 ForEach-Object
最慢。请注意,代码从 this Gist 下载并定义 Time-Command
函数(我可以向你保证这样做是安全的,但你应该始终自己检查源代码):
# Download and define the Time-Command function.
irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
Write-Verbose -vb "1,000 items, average of 10 runs"
$a=1..1000; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
Write-Verbose -vb "100,000 items, average of 10 runs"
$a=1..1e5; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
双核 Windows 10 虚拟机的结果,Windows PowerShell v5.1 / PowerShell Core 7.2.0-preview.6;请注意,绝对数字并不重要,会因许多变量而异,但 比率 (第 Factor
列)应该能让您有所了解。
Windows PowerShell v5.1:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013639
3.99 0.005 $a.ForEach({ (++$_) }) 00:00:00.0054464
7.46 0.010 $a | ForEach-Object { (++$_) } 00:00:00.0101785
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.014 foreach($e in $a) { (++$e) } 00:00:00.0144434
37.56 0.542 $a.ForEach({ (++$_) }) 00:00:00.5424872
62.61 0.904 $a | ForEach-Object { (++$_) } 00:00:00.9043278
PowerShell Core 7.2.0-preview.6:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013071
4.23 0.006 $a.ForEach({ (++$_) }) 00:00:00.0055324
8.04 0.011 $a | ForEach-Object { (++$_) } 00:00:00.0105058
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.010 foreach($e in $a) { (++$e) } 00:00:00.0095252
34.12 0.325 $a.ForEach({ (++$_) }) 00:00:00.3250133
57.83 0.551 $a | ForEach-Object { (++$_) } 00:00:00.5508560
注意:在发现原始方法中的缺陷后,已更新上述基准。新的数字导致不同的结论。
一般观察:
foreach
是迄今为止最快的,其次是.ForEach()
,ForEach-Object
是迄今为止最慢的- 注意:虽然这是预期的,但考虑到管道引入了开销,减速在很大程度上归因于低效的实现
ForEach-Object
(和Where-Object
)从 PowerShell 7.2 开始的 cmdlet - 请参阅 this blog post for an excellent analysis, which led to GitHub feature request #10982.
- 注意:虽然这是预期的,但考虑到管道引入了开销,减速在很大程度上归因于低效的实现
的两倍左右foreach
的性能优势随着迭代次数的增加而增长,与大数相当可观。然而,与迭代次数无关,.ForEach()
似乎是ForEach-Object
.就绝对计时而言,PowerShell Core 似乎比 Windows 具有较大迭代次数的 PowerShell 表现更好。
在 macOS 上(上面未显示结果),减速因素似乎更大,而且执行速度似乎也从绝对值来看更慢。
Re-运行 同一 PowerShell 会话中的测试扩大了性能差距,表明只有
foreach
语句受益于按需编译。
[1] 例如,对比使用 cmdlet Get-Content
vs. with language statement switch
-File
; or contrasting filtering a collection with cmdlet Where-Object
vs. via method .Where()
or operator -match
.