PowerShell的Set-Content和Out-File有何区别?

108
在PowerShell中,Out-FileSet-Content的区别是什么?或者Add-ContentOut-File -append呢?我发现如果对同一个文件使用两个命令,文本将被完全乱码。(第二个问题: >Out-File的别名,对吗?)
7个回答

113

通过几个月使用PowerShell和一些科学实验,我总结了以下内容。我从未在文档中找到过这些 :(

[更新:现在很多情况都有更好的记录了。]

读写锁定

Out-File 运行时,另一个应用程序可以读取日志文件。

Set-Content 运行时,其他应用程序无法读取日志文件。 因此,永远不要使用 Set-Content 记录运行时间较长的命令。

编码

Out-File 默认保存为 Unicode (UTF-16LE) 编码(尽管可以指定),而 Set-Content 在 PowerShell 3+ 中默认使用 ASCII (US-ASCII)(也可以指定)。 在早期的 PowerShell 版本中,Set-ContentDefault (ANSI) 编码编写内容。

编辑说明:尽管文档声称,PowerShell 5.1 版默认使用区域特定的 Default(“ANSI”)编码,但实际上并非如此。 如果 ASCII 是默认值,则诸如 ü 的非 ASCII 字符将被转换为文字 ?,但这是事实:'ü' | Set-Content tmp.txt; (Get-Content tmp.txt) -eq '?' 得到 $False

PS > $null | out-file outed.txt
PS > $null | set-content set.txt
PS > md5sum *
f3b25701fe362ec84616a93a45ce9998 *outed.txt
d41d8cd98f00b204e9800998ecf8427e *set.txt

这意味着两个命令的默认设置不兼容,混合使用它们会破坏文本,因此始终要指定编码。

格式化

正如Bartek所解释的那样,Out-File 保存输出在终端中看到的花哨格式。因此,在一个包含两个文件的文件夹中,命令 dir | out-file out.txt 创建了一个包含11行的文件。

Set-Content 则保存一个更简单的表示。在那个包含两个文件的文件夹中,命令 dir | set-content sc.txt 创建了一个包含两行的文件。要模拟终端中的输出:

PS > dir | ForEach-Object {$_.ToString()}
out.txt
sc.txt

我相信这种格式化会对换行产生影响,但我还不能描述它。

文件创建

Set-Content 在创建空文件时不如 Out-File 可靠:

在一个空文件夹中,命令 dir | out-file out.txt 会创建一个文件,而 dir | set-content sc.txt 则不会。

管道变量

Set-Content 从管道中取出文件名,并允许你将多个文件的内容设置为某个固定值。

Out-File 从管道中获取数据,更新单个文件的内容。

参数

Set-Content 包括以下额外参数:

  • Exclude
  • Filter
  • Include
  • PassThru
  • Stream
  • UseTransaction

Out-File 包括以下额外参数:

  • Append
  • NoClobber
  • Width

有关这些参数的更多信息,请参阅帮助文档;例如:get-help out-file -parameter append


4
Set-Content 默认的编码格式翻译为 (Get-Culture).Textinfo.ANSICodePage(在 Windows 8.1,Powershell 4.0 版本下,当前语言区域是 cs-CZ,当前用户界面区域是 en-GB,使用 ANSICodePage 1250 ,OEMCodePage 852 进行测试,测试所用字符串为 'řž',并分别采用不同的代码页进行测试)。 - JosefZ
1
请注意,在某些情况下,Out-File 会出现长行问题。例如:$x = [pscustomobject]@{A=('a' * 500); B=('b' * 500)}; $x | Out-File -Path myfile.txt - Bacon Bits

20

Out-File 的行为是覆盖输出路径,除非设置了 -NoClobber 和/或 -Append 标志。如果输出路径已经存在,则默认情况下(如果可以),Add-Content 将添加内容。两者都将创建文件,如果文件不存在的话。

另一个有趣的区别是,Add-Content 默认会创建一个ASCII编码的文件,而Out-File 默认会创建一个小端Unicode编码的文件。

>一个别名 的语法糖,用于 Out-File。它是具有一些预定义参数设置的 Out-File


谢谢,了解编码差异很有用。你说的不太对,如果你执行 echo "" > $null | Add-Content abc.txt,它 不会 创建文件 abc.txt,而 Out-File 会创建。 - Colonel Panic
@MattHickford 这是一个有点奇怪的边缘情况。该代码将管道传输到 $null,因此 Add-Content 不会收到任何内容。如果 Add-Content 没有收到任何内容,为什么它要创建一个文件呢?另一方面,同样的问题也可以问到 Out-File。 - Andy Arismendi
对我来说,区别很重要。gci $folder | Out-File log.txt ; cat log.txt 可以工作,而 gci $folder | Add-Content log.txt ; cat log.txt 会崩溃。 - Colonel Panic
@MattHickford 在尝试处理文件之前,我可能会确保该文件存在。这对所有编程语言来说都是一个好习惯。 - Andy Arismendi
另一个区别是,在使用 Set-Content 时,该文件对其他应用程序不可用。 - Colonel Panic

10

好的,我不同意... :)

  1. Out-File有-Append选项(-NoClober可用于避免覆盖),它将使用Add-Content添加内容,但这不是完全相同的东西。
  2. command | Add-Content将在输入上使用.ToString() 方法。Out-File将使用默认格式。

所以:

ls | Add-Content test.txt

ls | Out-File test.txt

会给你完全不同的结果。

而且,'>' 不是别名,它是重定向运算符(其他 shell 中也是如此)。并且有非常严重的限制……它将以与显示方式相同的方式截取行。Out-File 有一个 -Width 参数,可以帮助你避免这种情况。另外,使用重定向运算符时,你无法决定要使用哪种编码。

希望对你有所帮助 Bartek


3
这是一个别名,意思是 > 和 Out-File 是同一件事情。它们调用相同的代码。来自 Bruce Payette 的《PowerShell in Action Second Edition》(Kindle 位置 4646):实际上,“myScript > file.txt” 只是“语法糖”,等价于 “myScript | out-file -path file.txt”。在某些情况下,您可能希望直接使用 Out-File,因为它可以更好地控制输出的方式。 - Andy Arismendi
1
关于默认格式(Out-File)与ToString(Add-Content)的好处 - Andy Arismendi
我的观点是:尽管两者通常都是相同的,但在PowerShell中,别名具有其含义...因此,我不会使用这个术语来描述它们之间的关系.. ;) 别名替换命令,在这种情况下,它应该使语法:ls | > file.txt 可能。显然,那行不通... - BartekB
1
默认格式化是指在控制台中呈现给定对象的方式。大多数核心 cmdlet/对象类型都具有格式化元数据,这些元数据告诉 PowerShell 如何以用户友好的方式显示它们。换句话说:将命令的结果通过管道传递到 Out-File 可以用于将命令的输出保存到文件中,而不会丢失 PowerShell 所做的格式化。 - BartekB
2
是的,我认为这是一个重要的区别,即>并不是out-file的精确等价物。如果您设置$PSDefaultParameterValues["Out-File:Encoding"] = "UTF8",它将被>忽略。 - wisbucky
显示剩余3条评论

4

Set-Content支持-Encoding Byte,而Out-File不支持。

因此,当您想要将二进制数据或Text.Encoding#GetBytes()的结果写入文件时,应该使用Set-Content


1

关于编码差异的补充:

使用 PowerShell 5.1 的 Windows:

  • Out-File - 默认编码为 utf-16le
  • Set-Content - 默认编码为 us-ascii

使用 PowerShell 7.1 的 Linux:

  • Out-File - 默认编码为 us-ascii
  • Set-Content - 默认编码为 us-ascii

0

Out-file -append 或者 >> 实际上可以在同一个文件中混合两种编码。即使文件最初是 ASCII 或 ANSI,它也会默认在底部添加 Unicode。Add-content 会在追加之前检查编码并进行匹配。顺便说一下,export-csv 默认为 ASCII(无重音符号),而 set-content/add-content 默认为 ANSI。


0
TL;DR,使用Set-Content,因为它比Out-File更一致。
  1. Set-Content 的行为在不同的 PowerShell 版本中是相同的。
    正如 @JagWireZ 所说,Out-File 在默认设置下即使在相同的操作系统(Windows)上也会产生不同的编码。powershell 5.1powershell 7.3 的文档说明编码从 unicode 更改为 utf8NoBOM

  2. 使用 Out-File 可能会导致一些问题,例如 Malformed XML,当然可以通过设置所需的编码来解决这些问题,但很可能会忘记设置编码而导致问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接