Powershell的Out-File在文件顶部添加了一个换行符 - Out-File与Set-Content

时间:2017-02-24 22:33:00

标签: powershell file-io

我有以下powershell:

# Find all .csproj files 
$csProjFiles = get-childitem ./ -include *.csproj -recurse 

# Remove the packages.config include from the csproj files.
$csProjFiles | foreach ($_) {(get-content $_) | 
             select-string -pattern '<None Include="packages.config" />' -notmatch | 
             Out-File $_ -force}

似乎工作正常。运行后,packages.config中的行不在文件中。

但是在我运行之后,该文件的 TOP 还有一个额外的换行符。 (不是底部。)

我很困惑如何到达那里。 如何摆脱文件顶部生成的额外换行符?

更新:

我换了一种不同的做法:

$csProjFiles | foreach ($_) {$currentFile = $_; (get-content $_) | 
               Where-Object {$_ -notmatch '<None Include="packages.config" />'} | 
               Set-Content $currentFile -force}

它工作正常,并且文件顶部没有额外的行。但我不介意为什么最好的例子是添加额外的行。

1 个答案:

答案 0 :(得分:4)

  • Out-File和重定向操作符> / >> 获取任意输入对象并将其转换为字符串表示形式控制台 - 即 PowerShell 默认输出格式已应用 - 并将这些字符串表示形式发送到输出文件。
    这些字符串表示通常具有可读性的前导和/或尾随新行

  • Set-Content 适用于输入对象 已经是字符串应该被视为字符串 < /强>

    • PowerShell在所有输入对象上调用.psobject.ToString()以获取字符串表示形式,在大多数情况下,该表示形式遵循基础.NET类型的.ToString()方法。

结果表示通常相同,了解何时选择哪个cmdlet /运算符非常重要。

此外,默认字符编码不同

  • Out-File> / >>默认为UTF-16 LE ,PowerShell在可选Unicode的上下文中调用-Encoding 1}}参数。
  • Set-Content默认使用您系统的遗产&#34; ANSI&#34;代码页(单字节,扩展ASCII代码页),PowerShell调用Default

    • 请注意,PSv5.1中的the docs错误地声称默认值为 ASCII [1]

更改编码

  • Ad-hoc 更改:将 -Encoding参数Out-File或{{1}一起使用明确控制输出字符编码 您无法更改Set-Content / > ad-hoc 使用的编码,但请参见下文。

  • [PSv3 +] 更改默认 (谨慎使用):使用>>机制(请参阅{ {3}}),可以为参数设置默认值

    • 更改$PSDefaultParameterValues的默认编码也会更改PSv5.1或更高版本中的Out-File / > [2]
      例如,要将其更改为UTF-8,请使用:
      >>

      • 请注意,在PSv5.0或更低版本 无法更改编码$PSDefaultParameterValues['Out-File:Encoding']='UTF8'>使用的内容。
    • 如果您更改>>的默认设置,请务必将其更改为Set-Content
      Add-Content

    • 您还可以使用通配符模式表示要应用默认参数值的cmdlet /高级函数名称;例如,如果您使用$PSDefaultParameterValues['Set-Content:Encoding'] = $PSDefaultParameterValues['Add-Content:Encoding'] ='UTF8',则具有$PSDefaultParameterValues['*:Encoding']='UTF8'参数的所有 cmdlet将默认为该值,但这是不明智的,因为在某些cmdlet中{ {1}}指的是输入编码。

    • cmdlet之间没有单个共享前缀,用于写入允许定位所有输出 cmdlet 的文件,但是您可以为每个动词定义一个模式:
      -Encoding

    • 警告-Encoding全局范围内定义,因此您对其所做的任何修改都会全局生效 ,并影响后续命令 要限制对脚本/函数范围及其后代范围的更改,请使用本地 $enc = 'UTF8; $PSDefaultParameterValues += @{ 'Out-*:Encoding'=$enc; 'Set-*:Encoding'=$enc; 'Add-*:Encoding'=$enc; 'Export-*:Encoding'=$enc }变量,您可以将其初始化为哈希表从头开始($PSDefaultParameterValues),或初始化为全局值的克隆$PSDefaultParameterValues

在目前的情况下,输出对象是由$PSDefaultParameterValues = @{}输出的$PSDefaultParameterValues = $PSDefaultParameterValues.Clone()个实例:

  • 使用默认格式,与[Microsoft.PowerShell.Commands.MatchInfo]一样,它们在上方输出一个空行,下面有两个空行(多个实例在单个块之间的连续块中打印上面和下面的空行集。

  • 如果你在Select-String上调用Out-File,它们只评估匹配的行(没有原始路径前缀,因为输入是通过管道而不是通过.psobject.ToString() / Set-File 参数)作为文件名,没有前导或尾随空行。

也就是说,如果您将-Path-LiteralPath显式输出为字符串,那么您只需将| Select-Object -ExpandProperty Line| ForEach-Object Line显示为Out-FileSet-Content 1}}会产生相同的结果(默认编码除外)。

PS:LotPing的观察是正确的:您似乎将foreach 声明ForEach-Object cmdlet 混淆了(其中令人遗憾的是,内置别名foreach也会出现这种情况,导致混淆。)

Get-Help about_Parameters_DefaultValues并不需要$_的明确定义:在您传递给它的(隐含的-Process)脚本块中,$_自动定义为手头的输入对象。

($_) foreach的{​​{1}}参数有效忽略:因为它评估为ForEach-Object:自动变量{{1} },当在特殊上下文之外使用时 - 例如管道中的脚本块 - 有效地评估为$null,并且将$_放在它周围没有区别,所以你&#39 ;有效地传递$null,这是被忽略的。

[1]验证(...) 默认值如下:$null在en-US系统上产生ASCII,这是'0x{0:x}' -f $('ä' | Set-Content t.txt; $b=[System.IO.File]::ReadAllBytes("$PWD\t.txt")[0]; ri t.txt; $b)的Windows-1252代码点(与Unicode代码点重合,但输出是一个没有BOM的单字节编码文件)。
如果您明确使用0xe4,则会获得ä literal -Encoding ASCII的代码点,因为那是使用0x3f转换的内容所有非ASCII字符。至。 功能

[2] PetSerAl发现ForEach-Object cmdlet显示?的{​​{1}}和ASCII 有效别名,>指出重新定义>>因此也重新定义了Out-File [-Append] / Out-File;同样,>通过>>指定默认编码也会对$PSDefaultParameterValues / Out-File生效。
Windows PowerShell v5.1是以这种方式工作的最低版本..

source-code location寻求帮助的提示。