`cat somefile | Powershell中的cat`给出10000行而不是100行

时间:2019-02-05 23:03:05

标签: powershell

有人可以在这里解释我的误会吗? 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完全相同的内容。

2 个答案:

答案 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的源代码

enter image description here

因此,我认为故事是针对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

所以,我的猜测是对的。