有人可以在这里解释我的误会吗? cat somefile | cat
输出的是 10000 行,而不是 100行。我习惯了管道的Unix行为。这是重现问题的脚本(需要在PowerShell提示符下逐行输入):
seq 1 100 > somefile
cat somefile # works as expected, outputs 100 lines
cat somefile | Measure-Object # 100 lines, expected.
cat somefile | cat # OUTPUTS 10000 lines!!!
# wait did I really just see that
cat somefile | cat | Measure-Object
# 10000 lines??!!!
cat somefile | cat | cat | Measure-Object
# 57300 lines??? That's not even a pattern!
很明显,我不知道这里发生了什么。我期待bash的行为。我知道这样做cat somefile | cat
没有用,但这仍然令人惊讶。
扑朔迷离的行为是cat somefile | cat | cat | cat
总是提供与cat somefile
完全相同的内容。
答案 0 :(得分:3)
为方便起见,引入了cat
的别名Get-Content
(以使Unix用户对PowerShell更加满意)。但是,这并不能使Get-Content
的行为与Unix命令cat
完全相同。该cmdlet不会回显从管道输入的字符串:
PS C:\Temp> 'foo' | cat cat : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input. At line:1 char:9 + 'foo' | cat + ~~~
这就是Write-Output
(或其别名echo
)的用途:
PS C:\Temp> 'foo' | Write-Output foo
接受管道输入的Get-Content
的默认参数分别为-Path
和-LiteralPath
,它们都期望有效路径。
仔细检查Get-Content
的输出后,您会发现这些对象不仅具有字符串对象的常规属性,而且还具有一些属性,这些属性包含有关从中读取数据的文件的信息,特别是{ {1}}:
PS C:\Temp> 4..6 > out.txt PS C:\Temp> cat .\out.txt 4 5 6 PS C:\Temp> cat .\out.txt | Get-Member TypeName: System.String Name MemberType Definition ---- ---------- ---------- ... PSChildName NoteProperty string PSChildName=out.txt PSDrive NoteProperty PSDriveInfo PSDrive=C PSParentPath NoteProperty string PSParentPath=C:\Temp PSPath NoteProperty string PSPath=C:\Temp\out.txt PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem ReadCount NoteProperty long ReadCount=1 Chars ParameterizedProperty char Chars(int index) {get;} Length Property int Length {get;}
PSPath
属性是第二个PSPath
的输入,导致输入文件中的每一行触发同一文件的另一个Get-Content
。但是,第一个Get-Content
的输出对象也具有属性Get-Content
(指示已从文件读取的行数),该属性也恰好是{{1 }}。因此,第二个ReadCount
与第一个{em> 读取的文件完全不同。使用Get-Content
一次读取文件中的2行,使用Get-Content
一次读取文件中的3行,依此类推。
PS C:\Temp> cat .\out.txt | cat 4 # ← input line 1 ("4"), ReadCount = 1, 1st read (returns "4") 5 # ← input line 1 ("4"), ReadCount = 1, 2nd read (returns "5") 6 # ← input line 1 ("4"), ReadCount = 1, 3rd read (returns "6") 4 # ← input line 2 ("5"), ReadCount = 2, 1st read (returns "4", "5") 5 6 # ← input line 2 ("5"), ReadCount = 2, 2nd read (returns "6") 4 # ← input line 3 ("6"), ReadCount = 3, 1st read (returns "4", "5", "6") 5 6
由于附加的管道步骤(ReadCount=2
)不会产生n m 条输出行(ReadCount=3
是文件中的行数,{{1} }管道步骤的数量。
答案 1 :(得分:2)
我无法确切解释原因,但这里有些解释。
首先将文件$_FILE
设为变量,假设文件内容为cat
1..10
查看第一个元素的对象属性,我们将看到属性$t = cat .\somefile # 1..10
,
ReadCount
查看# $t | gm
$t[0].ReadCount # 1
$t[1].ReadCount # 2
$t[2].ReadCount # 3
# ...
或Get-Content
的源代码
因此,我认为故事是针对cat
中的每个元素的,例如$t
到$t[2] # 3
的管道,cat
从管道中设置cat
并再次读取文件意味着下面的命令。
ReadCount
对于下一个cat -Path .\somefile -ReadCount 3
,$t[3]
为4,ReadCount
表示类似的命令
cat
在Windows PowerShell上,对于文件cat -Path .\somefile -ReadCount 4
,我们可以得到的行数是57300,但是1..100
列出了2008个对象(因为measure
计算的是对象号,而不是行号)。
measure-object
所以,我的猜测是对的。