如何在PowerShell中连接两个文本文件?

143

我正在尝试复制Unix中cat命令的功能。

我希望避免使用显式读取两个文件到变量中、将变量连接在一起,然后写出连接后的变量的解决方案。


1
关于通过复制操作合并文件的相关问题,请参考以下链接:https://dev59.com/-HANtIcB2Jgan1znz75W - mklement0
11个回答

237

只需使用Get-ContentSet-Content cmdlet:

Get-Content inputFile1.txt, inputFile2.txt | Set-Content joinedFile.txt

你也可以使用这种方式连接两个以上的文件。

如果源文件的命名类似,你可以使用通配符:

Get-Content inputFile*.txt | Set-Content joinedFile.txt

注意1: PowerShell 5及更早版本允许使用别名catsc来更简洁地执行Get-ContentSet-Content。然而,这些别名存在问题,因为cat是*nix系统中的系统命令,在Windows系统中sc是一个系统命令 - 因此不建议使用它们,实际上在PowerShell Core(v7)中sc甚至已经被取消定义了。PowerShell团队总体上不建议使用别名

注意2: 小心使用通配符 - 如果你尝试输出到inputFiles.txt(或类似匹配模式的文件),PowerShell会进入一个无限循环!(我刚测试过。)

注意3: 使用>输出到文件时不能保留字符编码!这就是为什么推荐使用Set-Content的原因。


7
如果有人想使用“_Get-ChildItems | Foreach-Object_”结构迭代文件,为了避免每次迭代都覆盖目标文件,您可能需要使用Add-Content而不是Set-Content。请注意,Add-Content将内容附加到文件末尾,而不是覆盖整个文件。 - Jonas
4
请注意,Set-Content 命令默认使用本地代码页(例如英语的 Windows-1252)。如果源文件包含其他编码方式(例如 Windows-1251 或 UTF8),您必须设置正确的编码方式,如 sc file.txt -Encoding UTF8(自 v6.2 版本开始支持俄语等数字编码方式)。 - Radek Pech
1
@Jonas,“Add-Content”命令的问题在于,如果您运行该命令两次,则聚合文件的长度将增加一倍。一个很好的替代品是“Out-File”。示例在这里 - Dan Friedman
2
如果文件是二进制的(例如,我这种情况下的zipfile的某些部分),似乎无法工作。 - Daniel Lidström
4
@DanielLidström 如果使用正确的参数,这个方法也适用于二进制文件:Get-Content my.bin -Raw | Set-Content my.bin -NoNewline 不会改变 my.bin 除了时间戳以外。选项 -Raw 保留任何回车符/换行符字节,而 -NoNewline 则防止 PowerShell 添加它自己的回车符/换行符字节。 - stackprotector
显示剩余4条评论

63

不要使用 >,否则会破坏字符编码。应该使用:

Get-Content files.* | Set-Content newfile.file

1
catGet-Content 的别名。 - n0rd
5
我认为更多是“使用管道而不是其他方式”的意思。 - ksoo
可以确认。当使用 > 时,我的连接文件开头会出现 ÿþ,即 FF FE - gpresland
1
>Out-File 的有效别名,在 Windows PowerShell 中默认为“Unicode”(UTF-16LE),而 Set-Content 默认为系统的传统 ANSI 代码页。虽然后者的编码问题较少,但请注意,两个 cmdlet 都有可能改变输入文件的编码,因为它们的默认编码与输入文件的编码无关(这是 PowerShell 不提供的信息)。请注意,PowerShell (Core) 7+ 现在幸运地默认使用(无 BOM)UTF-8,在所有 cmdlet 中保持一致。 - mklement0

26
cmd 中,你可以这样做:
copy one.txt+two.txt+three.txt four.txt

在PowerShell中,这将是:
cmd /c copy one.txt+two.txt+three.txt four.txt

虽然使用 gc 是 PowerShell 的方法,但以上方法对于大文件来说非常快。而且可以使用 /B 开关来处理非 ASCII 文件。

3
对我来说,cat命令的执行时间比cmd /c命令长了几个数量级(后者非常快);感谢指出这个选项! - Rob
1
这是最好的答案。 - Nicholas DiPiazza
1
你应该在目标文件中添加 /b 以防止字节 0x1A 被添加到文件末尾:copy one.txt+two.txt+three.txt four.txt /b。请参见此问答 - stackprotector

15
你可以使用 Add-Content 命令。这种方法可能会比其他解决方案快一点,因为我不需要检索第一个文件的内容。
gc .\file2.txt| Add-Content -Path .\file1.txt

gc 是指什么? - octopusgrabbus
1
gc 是 Get-Content 的别名。 - MM.
gc (Get-Content) 默认按行检索文件内容。请使用 Set-Content 而不是 Add-Content,因为后者会保留输出文件中的任何现有内容。请注意,在输出文件中可能会出现不同的字符编码(无论您使用哪个 cmdlet),如接受答案评论中所讨论的。 - mklement0

11

在命令提示符中连接文件的方法是:

type file1.txt file2.txt file3.txt > files.txt

PowerShell将type命令转换为Get-Content,这意味着在PowerShell中使用type命令时会出现错误,因为Get-Content命令需要用逗号分隔文件。相同的命令在PowerShell中应该是:

Get-Content file1.txt,file2.txt,file3.txt | Set-Content files.txt

5

我使用了:

Get-Content c:\FileToAppend_*.log | Out-File -FilePath C:\DestinationFile.log 
-Encoding ASCII -Append

这个附加的很好。我添加了ASCII编码以去除Notepad++显示的空字符,而不需要显式编码。


5
如果您需要按照特定参数(例如日期时间)排序文件:
gci *.log | sort LastWriteTime | % {$(Get-Content $_)} | Set-Content result.log

4
保持编码方式和行尾格式:
Get-Content files.* -Raw | Set-Content newfile.file -NoNewline

注意:AFAIR的参数不受旧版本的Powershell(<3? <4?)支持。

我发现在你提供的命令末尾添加-Encoding unicode(除了你提供的两个参数之外)可以让Excel正确打开一组CSV文件。更多信息请参见https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-content?view=powershell-7.2#parameters。 - zylstra

3

由于其他回答中通常会因为管道符而格式错误,最安全的做法如下:

add-content $YourMasterFile -value (get-content $SomeAdditionalFile)

我知道你希望避免将$SomeAdditionalFile的内容读入变量,但为了保存例如换行格式,我认为没有适当的方法可以在不使用变量的情况下完成。

一个解决方法是逐行遍历$SomeAdditionalFile并将其导入$YourMasterFile。然而这种方法过于资源密集。


3
您可以像这样做:

您可以执行以下操作:

get-content input_file1 > output_file
get-content input_file2 >> output_file

在这里>是“out-file”的别名,而>>是“out-file -append”的别名。


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