简体   繁体   English

为什么 Powershell 的 Set-Content -Value 参数不能正确读取管道变量

[英]Why does Powershell's Set-Content -Value argument not read Pipeline Variable correctly

So I'm trying to get the contents of a bunch of files to replace the header string:所以我试图获取一堆文件的内容来替换 header 字符串:

$replaces = dir | select Name, @{n='content';e={(get-content $_) -replace "header-foo","header-bar"}}

That then gives me a list of:然后给了我一个列表:

Name       Content
----       ----------
a.txt      header-foo blah blah
b.txt      header-foo blah blah blah
c.txt      header-foo blah

Then I want to pass the value of this to set-content -value like so:然后我想将 this 的值传递给 set-content -value,如下所示:

$replaces | set-content -Path {"alt/" + $_.Name} -Value {$_.content}

Only all of my files have the content $_.content now.现在只有我所有的文件都有内容$_.content I also tried -Value ($_.content) but that doesn't do the right thing either.我也试过-Value ($_.content)但这也不是正确的事情。

It's only when I use a foreach does it work:只有当我使用 foreach 时它才会起作用:

$replaces | foreach { set-content -Path ("alt/" + $_.Name) -Value $_.content }

Why is this the case?为什么会这样? Why does it not work correctly without the foreach ?为什么没有foreach就不能正常工作?

You're trying to use a delay-bind script block ( {... } ) in order to dynamically determine the argument for Set-Content 's -Value parameter, based on each pipeline input object.您正在尝试使用延迟绑定脚本块( {... } ) ,以便根据每个管道输入 object 动态确定Set-Content-Value参数的参数。

However, delay-bind script blocks cannot be used with -Value , because that parameter's type is [object[]] ( System.Object[] ) (see Get-Help -Parameter Value Set-Content );但是,延迟绑定脚本块不能与-Value一起使用,因为该参数的类型是[object[]] ( System.Object[] ) (请参阅Get-Help -Parameter Value Set-Content ); the same limitation applies to [scriptblock] -typed parameters.同样的限制适用于[scriptblock]类型的参数。

To work around this limitation, you do need a loop-like construct in order to invoke Set-Content once for every intended -Value argument , as you have done with the ForEach-Object (whose built-in alias is foreach ) cmdlet.要解决此限制,您确实需要一个类似循环的构造,以便为每个预期的-Value参数调用一次Set-Content ,就像您使用ForEach-Object (其内置别名是foreach )cmdlet 所做的那样。


The reason that [object] and [scriptblock] parameters (and their array variants) do not work as delay-bind script blocks is that passing as script block to such parameters binds it instantly, as-is , because the argument type matches the parameter type. [object][scriptblock]参数(及其数组变体)不能作为延迟绑定脚本块工作的原因是,作为脚本块传递给此类参数会立即将其绑定,因为参数类型与参数匹配类型。

With any other parameter type - assuming that the parameter is designated as accepting pipeline input - PowerShell infers that a script-block argument is a delay-bind script block and evaluates the script block for each pipeline input object , as intended, and the script block must then ensure that its output is of a type that matches the target parameter.对于任何其他参数类型 - 假设参数被指定为接受管道输入 - PowerShell 推断脚本块参数是延迟绑定脚本块并评估每个管道输入 object的脚本块,如预期的那样,以及脚本块然后必须确保其 output 是与目标参数匹配的类型。

You problem is in "get-content $ " you must use get-content $ .Name你的问题是在 "get-content $ " 你必须使用 get-content $ .Name

But you should modify you script like this:但是你应该像这样修改你的脚本:

  1. Use Get-childItem (norme powershell)使用 Get-childItem (norme powershell)
  2. Use -file for take only file and not directory使用 -file 只获取文件而不是目录
  3. Use FullName, you can then use recurse if necessary使用 FullName,然后可以在必要时使用递归
  4. Use.Replace and not -replace operator (doesnt work in this case) Use.Replace 而不是 -replace 运算符(在这种情况下不起作用)

-replace use regular expression: detail here -replace 使用正则表达式: 这里有详细信息

$replaces = Get-ChildItem -file | select FullName, @{n='content';e={(get-content $_.FullName).Replace('header-foo', 'header-bar')}}
$replaces | %{set-content -Path $_.FullName -Value $_.content}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM