`кошка куда-нибудь |cat` в powershell дает 10000 строк вместо 100 - PullRequest
0 голосов
/ 06 февраля 2019

Может кто-нибудь объяснить, пожалуйста, мое недоразумение здесь?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, но это все еще удивительно.

Поведение Bash будет cat somefile | cat | cat | cat всегда дает точно такой же контент, что и cat somefile.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Псевдоним cat для Get-Content был введен по соображениям удобства (я полагаю, чтобы пользователи Unix чувствовали себя более комфортно с PowerShell).Это не заставляет Get-Content вести себя точно так же, как команда Unix cat.Командлет, в частности, не отображает ввод строки из конвейера:

PS C:\Temp> <b>'foo' | cat</b>
<i>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.</i>
At line:1 char:9
+ 'foo' | cat
+         ~~~

Вот для чего Write-Output (или его псевдоним echo):

PS C:\Temp> <b>'foo' | Write-Output</b>
foo

Параметры по умолчаниюGet-Content, которые принимают входные данные конвейера, равны -Path и -LiteralPath соответственно, оба из которых ожидают допустимый путь.

При более внимательном рассмотрении вывода Get-Content вы заметите, что объекты имеютне только обычные свойства строковых объектов, но также некоторые свойства с информацией о файле, из которого были прочитаны данные, в частности PSPath:

PS C:\Temp> <b>4..6 > out.txt</b>
PS C:\Temp> <b>cat .\out.txt</b>
4
5
6
PS C:\Temp> <b>cat .\out.txt | Get-Member</b>

   TypeName: System.String

Name             MemberType            Definition
----             ----------            ----------
...
<i>PSChildName      NoteProperty          string PSChildName=out.txt
PSDrive          NoteProperty          PSDriveInfo PSDrive=C
PSParentPath     NoteProperty          string PSParentPath=C:\Temp
<b>PSPath           NoteProperty          string PSPath=C:\Temp\out.txt</b>
PSProvider       NoteProperty          ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem</i>
ReadCount        NoteProperty          long ReadCount=1
Chars            ParameterizedProperty char Chars(int index) {get;}
Length           Property              int Length {get;}

Свойство PSPath является тем, что служит входомдля второго Get-Content, вызывая каждую строку из входного файла для запуска другого Get-Content того же файла.Однако выходные объекты из первого Get-Content также имеют свойство ReadCount (указывающее количество строк, которые уже были прочитаны из файла), что также является параметром Get-Content.Из-за этого второй Get-Content не читает входной файл точно так же, как первый.При ReadCount=2 считываются 2 строки из файла за раз, при ReadCount=3 по 3 строки читаются одновременно и т. Д.

PS C:\Temp> <b>cat .\out.txt | cat</b>
4   <i># &larr; input line 1 ("4"), ReadCount = 1, 1st read (returns "4")</i>
5   <i># &larr; input line 1 ("4"), ReadCount = 1, 2nd read (returns "5")</i>
6   <i># &larr; input line 1 ("4"), ReadCount = 1, 3rd read (returns "6")</i>
4   <i># &larr; input line 2 ("5"), ReadCount = 2, 1st read (returns "4", "5")</i>
5
6   <i># &larr; input line 2 ("5"), ReadCount = 2, 2nd read (returns "6")</i>
4   <i># &larr; input line 3 ("6"), ReadCount = 3, 1st read (returns "4", "5", "6")</i>
5
6

Из-за этого выполняются дополнительные шаги конвейера (cat .\out.txt | cat | cat ...) не выводить n m строк вывода (n - количество строк в файле и m количество шагов конвейера).

0 голосов
/ 06 февраля 2019

Я не могу точно объяснить, почему, но вот несколько копий.

Сначала 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

enter image description here

Итак, я думаю, что история для каждого элемента в $t, например, $t[2] # 3 конвейер к cat, cat установка ReadCount из конвейера и чтение файласнова подразумевают следующую команду.

cat -Path .\somefile -ReadCount 3

Для следующих $t[3], ReadCount равно 4, cat подразумевает аналогичную команду

cat -Path .\somefile -ReadCount 4

В Windows PowerShell для файла 1..100, мы можем получить число строк 57300, но measure список объектов 2008 (потому что measure-object считает количество объектов, а не номер строки).

cat .\somefile | cat | cat |measure
Count    : 2008
Average  :
Sum      :
Maximum  :
Minimum  :
Property :
@((cat .\somefile | cat | cat)  | %{$_}).count
57300

Итак, я думаю, что это правильно, я думаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...