为什么 Powershell 的 Set-Content -Value 参数不能正确读取管道变量
Why does Powershell's Set-Content -Value argument not read Pipeline Variable correctly
所以我试图获取一堆文件的内容来替换 header 字符串:
$replaces = dir | select Name, @{n='content';e={(get-content $_) -replace "header-foo","header-bar"}}
然后给了我一个列表:
Name Content
---- ----------
a.txt header-foo blah blah
b.txt header-foo blah blah blah
c.txt header-foo blah
然后我想将它的值传递给 set-content -value 像这样:
$replaces | set-content -Path {"alt/" + $_.Name} -Value {$_.content}
现在只有我所有的文件都有 $_.content
的内容。我也试过 -Value ($_.content)
但这也不行。
只有当我使用 foreach 时它才起作用:
$replaces | foreach { set-content -Path ("alt/" + $_.Name) -Value $_.content }
为什么会这样?为什么没有 foreach
就不能正常工作?
你的问题在“get-content $”你必须使用get-content $.Name
但是你应该像这样修改你的脚本:
- 使用 Get-childItem(标准 powershell)
- 使用 -file 只获取文件而不是目录
- 使用全名,必要时可以使用递归
- 使用 .Replace 和 not -replace 运算符(在这种情况下不起作用)
-替换使用正则表达式:detail here
$replaces = Get-ChildItem -file | select FullName, @{n='content';e={(get-content $_.FullName).Replace('header-foo', 'header-bar')}}
$replaces | %{set-content -Path $_.FullName -Value $_.content}
您正在尝试根据每个管道输入对象使用 ({ ... }
) in order to dynamically determine the argument for Set-Content
的 -Value
参数。
但是,delay-bind 脚本块不能与 -Value
一起使用,因为该参数的类型是 [object[]]
(System.Object[]
) (见 Get-Help -Parameter Value Set-Content
);同样的限制适用于 [scriptblock]
类型的参数。
要解决此限制,您确实需要一个类似循环的构造,以便为每个预期的 -Value
参数调用 Set-Content
一次,正如您对 ForEach-Object
(其内置别名是 foreach
)cmdlet 所做的那样。
[object]
和 [scriptblock]
参数(及其数组变体)不能用作延迟绑定脚本块的原因是作为脚本块传递给此类参数会绑定它 立即按原样,因为参数类型与参数类型匹配。
对于任何其他参数类型 - 假设参数被指定为接受管道输入 - PowerShell 推断脚本块参数是延迟绑定脚本块并为每个管道评估脚本块 按预期输入对象,然后脚本块必须确保其输出的类型与目标参数匹配。
所以我试图获取一堆文件的内容来替换 header 字符串:
$replaces = dir | select Name, @{n='content';e={(get-content $_) -replace "header-foo","header-bar"}}
然后给了我一个列表:
Name Content
---- ----------
a.txt header-foo blah blah
b.txt header-foo blah blah blah
c.txt header-foo blah
然后我想将它的值传递给 set-content -value 像这样:
$replaces | set-content -Path {"alt/" + $_.Name} -Value {$_.content}
现在只有我所有的文件都有 $_.content
的内容。我也试过 -Value ($_.content)
但这也不行。
只有当我使用 foreach 时它才起作用:
$replaces | foreach { set-content -Path ("alt/" + $_.Name) -Value $_.content }
为什么会这样?为什么没有 foreach
就不能正常工作?
你的问题在“get-content $”你必须使用get-content $.Name
但是你应该像这样修改你的脚本:
- 使用 Get-childItem(标准 powershell)
- 使用 -file 只获取文件而不是目录
- 使用全名,必要时可以使用递归
- 使用 .Replace 和 not -replace 运算符(在这种情况下不起作用)
-替换使用正则表达式:detail here
$replaces = Get-ChildItem -file | select FullName, @{n='content';e={(get-content $_.FullName).Replace('header-foo', 'header-bar')}}
$replaces | %{set-content -Path $_.FullName -Value $_.content}
您正在尝试根据每个管道输入对象使用 { ... }
)Set-Content
的 -Value
参数。
但是,delay-bind 脚本块不能与 -Value
一起使用,因为该参数的类型是 [object[]]
(System.Object[]
) (见 Get-Help -Parameter Value Set-Content
);同样的限制适用于 [scriptblock]
类型的参数。
要解决此限制,您确实需要一个类似循环的构造,以便为每个预期的 -Value
参数调用 Set-Content
一次,正如您对 ForEach-Object
(其内置别名是 foreach
)cmdlet 所做的那样。
[object]
和 [scriptblock]
参数(及其数组变体)不能用作延迟绑定脚本块的原因是作为脚本块传递给此类参数会绑定它 立即按原样,因为参数类型与参数类型匹配。
对于任何其他参数类型 - 假设参数被指定为接受管道输入 - PowerShell 推断脚本块参数是延迟绑定脚本块并为每个管道评估脚本块 按预期输入对象,然后脚本块必须确保其输出的类型与目标参数匹配。