Что является эквивалентом cat -n Баша в PowerShell?

3209
deostroll

Я хочу catфайл и вывести номер строки каждой строки, которую он выводит.

Однако в PowerShell catвыводит массив. Отсюда возникает вопрос: как мне распечатать индекс каждого элемента, пока он выводится на консоль ...?

Я попробовал что-то вроде этого:

$k = cat foo.js $k | foreach { $index = $k.IndexOf($_) + 1; write "$index : $_"; } | more 

Это дало мне странные результаты. Некоторые номера строк повторяются. Что такое элегантный и более надежный способ сделать это?

7
`cat -n` на самом деле не является частью bash - это часть` cat`, которая является отдельной программой, и нет никаких оснований полагать, что каждая машина с установленным bash будет поддерживать ее. Charles Duffy 6 лет назад 4

7 ответов на вопрос

11
BartekB

Вы потенциально злоупотребляете Select-String для этого:

Select-String -Pattern .* -Path .\foo.txt | select LineNumber, Line 

Пример вывода:

LineNumber Line ---------- ---- 1 a  2  3 b  4  5 c  
классный декларативный код в отличие от других ответов cat 6 лет назад 0
5
DavidPostill

Я хочу отследить файл и вывести номер строки каждой строки, которую он выводит.

Используйте следующую команду:

$counter = 0; get-content .\test.txt | % { $counter++; write-host "`t$counter` $_" } 

Как указано в комментариях:

  • Может быть лучше использовать write-outputвместо, write-hostпоскольку это позволяет дальнейшую обработку вывода.
  • echo это псевдоним для write-output

Таким образом, приведенная выше команда становится:

$counter = 0; get-content .\test.txt | % { $counter++; echo "`t$counter` $_" } 

Пример вывода:

> type test.txt foo //approved bar // approved foo /* approved */ bar  > $counter = 0; get-content .\test.txt | % { $counter++; echo "`t$counter` $_" } 1 foo 2 //approved 3 bar 4 // approved 5 foo 6 /* 7 approved 8 */ 9 bar > 

Пример вывода из Cygwin cat -nдля сравнения:

$ cat -n test.txt 1 foo 2 //approved 3 bar 4 // approved 5 foo 6 /* 7 approved 8 */ 9 bar $ 
Хммм ... Да, я думаю, что это лучше, чем у меня. Хотя я мог бы изменить `Write-Host ...` на `" "-f $ counter, $ _` (и я до сих пор не могу заставить обратные галочки работать должным образом внутри обратного текста. ..) Jeff Zeitlin 6 лет назад 0
Write-Output был бы лучшим выбором здесь, чем write-host, если вы планируете отправлять данные в конвейер для сохранения или дальнейшей обработки. Zoredache 6 лет назад 0
@ Zoredache Вполне вероятно. Я не эксперт по PowerShell :) DavidPostill 6 лет назад 0
@DavidPostill По умолчанию проще использовать `echo` (который называется псевдонимом` Write-Output`). `Write-Host` это ... особенное. Это как писать напрямую в `/ dev / tty`. Bob 6 лет назад 0
@Bob Спасибо за объяснение. Я обновил ответ. DavidPostill 6 лет назад 0
1
Jeff Zeitlin

IndexOf()будет соответствовать первому вхождению значения, поэтому ваши повторяющиеся номера строк с использованием вашего исходного кода означают, что у вас есть несколько строк в файле, которые идентичны. Попробуйте следующее:

$k = Get-Content -Path foo.js $l = 0  while ($l -lt $k.length) { ": " -f $l,$k[$l] $l++ } 
1
Bewc

Все, о чем вы должны думать долго, не изящно. Таким образом, элегантность заключается в том, чтобы получить именно то, что вам нужно, поместить его в сценарий и вызвать сценарий, когда это необходимо. Чтобы решить эту проблему более элегантно и мощно, чем я сам, я использовал сценарий Джеффри Хикса здесь: http://jdhitsolutions.com/blog/scripting/445/more-fun-with-get-numberedcontent/

Пример: Get-NumberedContent. \ README.txt пример вывода:

369 | The Java(TM) Runtime Environment (JRE) and the JavaFX(TM) runtime are  370 | products of Sun Microsystems(TM), Inc.  371 |  372 | Copyright © 2008 Sun Microsystems, Inc.  373 | 4150 Network Circle, Santa Clara, California 95054, U.S.A.  374 | All rights reserved. 

Сценарий ниже на случай, если ссылка когда-либо не получится

#Requires -version 2.0  # Jeffery Hicks # http://jdhitsolutions.com/blog # follow on Twitter: http://twitter.com/JeffHicks # "Those who forget to script are doomed to repeat their work."  # **************************************************************** # * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * # * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * # * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * # * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * # ****************************************************************   Function Get-NumberedContent { #Requires -version 2.0  <# .Synopsis Display file contents in a numbered fashion. .Description This function will display the contents of a text file as numbered output. If the file is  a script file, commented lines will be displayed in Green. Unlike Get-Content, the output is written to the console using Write-Host. This function is primarily meant as a console  based file viewer.It does not write to the pipeline unless you use the -PassThru parameter in which case you will get no colorized output.   For script files, or any file for that matter, you can specify a character ad the comment character. The default comment character is the #. Any line that begins with that chara- cter will be treated as a comment. You can skip comments by using -NoComment. Otherwise  the line will print in a green font. You can override the fontcolor using -CommentColor.   Use -NoBlank to suppress output of any blank lines. You can also combine -NoBlank and  -NoComment to get a very short numbered line output.  Line 0 will display the full filename and path  .Parameter Filepath The filename and path. .Parameter CommentCharacter The character to use as the comment character. The default is #. The parameter has an  alias of "Char". .Parameter CommentColor The font color to use for commented lines. The default is green. This parameter has an alias of "Color" .Parameter NoComments If the file is a script file, -NoComments will suppress any lines that begin with the  appropriate comment character. .Parameter NoBlanks Suppress output of any blank lines. Line tabs and spacing will be maintained but blank lines will not be displayed. .Parameter Passthru Write the output to the pipeline.  .Example PS C:\> Get-NumberedContent c:\scripts\test.ps1  Display line numbered content of Test.ps1 using the default comment character (#) and the default comment color, Green. .Example PS C:\> Get-NumberedContent c:\scripts\update.vbs -nocomment -char "'"  Display the results of update.vbs without and lines that start with the comment character for VBS scripts. This expression is using the parameter alias CHAR for -CommentCharacter. .Example PS C:\> get-numberedcontent c:\files\report.ext -noblanks -pass | out-file NumReport.txt  Display the contents of c:\files\report.txt without any blank lines and pass to the pipeline. The pipelined output is then sent to the Out-File cmdlet. .Example PS C:\> dir c:\TEST\*.CSV | get-numberedcontent -commentCharacter ";" -commentColor "Red" -noblanks  Get the content for every CSV file in the Test directory. Commented lines that start with ; will be displayed in a red color and blank lines will be suppressed.  .Inputs Accepts strings as pipelined input .Outputs None  .Link Get-Content   .Notes NAME: Get-NumberedContent VERSION: 2.0 AUTHOR: Jeffery Hicks http://jdhitsolutions.com/blog LASTEDIT: 10/13/2009    #>   [CmdletBinding()]  param ( [Parameter( ValueFromPipeline=$True, Position=0, Mandatory=$True, HelpMessage="The filename and path of a text file.")]  [string]$Filename,  [Parameter( ValueFromPipeline=$False, Mandatory=$False, HelpMessage="The comment character for a specific file type.")]  [Alias("Char")] [string]$CommentCharacter="#",  [Parameter( ValueFromPipeline=$False, Mandatory=$False, HelpMessage="The comment character color. Default is Green.")]  [ValidateSet("Black","DarkBlue","Blue","DarkGreen","Green","DarkCyan","Cyan", "DarkRed","Red","Magenta","White","DarkGray","Gray","DarkYellow","Yellow")]  [Alias("Color")] [string]$CommentColor="Green",  [Parameter( ValueFromPipeline=$False, Mandatory=$False, HelpMessage="Suppress comment lines for script files.")]  [switch]$NoComment,  [Parameter( ValueFromPipeline=$False, Mandatory=$False, HelpMessage="Suppress blank lines.")]  [switch]$NoBlank,  [Parameter( ValueFromPipeline=$False, Mandatory=$False, HelpMessage="Write object to the pipeline instead of the console.")]  [switch]$Passthru  )  Begin { if ($NoComment) { Write-Debug "No comments"} if ($NoBlank)  Write-Debug "Comment character is #CommentCharacter" Write-Debug "Comment color is $CommentColor" if ($passthru)   } #end Begin  Process {  if ($_) { $Filename=$_ $FullName=$_.Fullname } else { $Fullname=$Filename }  write-debug "Testing $filename" If (Test-Path $filename) { $counter = -1  write-debug "Getting content" $content=get-content $Filename  #get the total number of lines and then the length #of that number so the number of leading zeros can be #calculated more accurately write-debug "Calculating number of lines" $c=($content.count).ToSTring().Length  write-debug "Padding line numbers to $c places" write-debug "Processing content" $content | foreach {  #default font color $fcolor="White"  #determine if line is a blank if ($_.Trim().Length -gt 0) { $Empty=$False write-debug "Line is not empty" } else { write-debug "Line is empty" $Empty=$True }   #determine if line is a comment  $isComment=$False  if ($_.Trim().StartsWith($CommentCharacter)) { write-debug "Comment line found" $fcolor=$CommentColor $isComment=$True }   if (($NoBlank -AND $Empty) -OR ($NoComment -AND $IsComment )) { write-debug "Skipping line" }  else {  $counter++  if ($counter -eq 0) { $line = " | " -f $counter,$FullName.ToUpper()  $fcolor="White"  }  else {  #write a line number with leading zeros the | bar and then the line of text from the file #trimming off any trailing spaces $line = " | " -f $counter,$_.TrimEnd() }  if ($Passthru) { write $line } else { Write-Host $line -foregroundcolor $fcolor } } #else not a blank line   } #end ForEach } #end if Test-Path else { Write-Warning "Failed to find $filename" } } #end Process  End { Write-Debug "Ending and exiting"  }  } #end function  Set-Alias gnc Get-NumberedContent 
1
LotPings

Аналогичен коду Дэвида Постилла, но с правильным правым числом, например, cat -n

$cnt=0;gc .\test.txt|%{$cnt++;" " -f $cnt,$_} 

Или с тем же результатом:

select-string -path .\test.txt "^" |%{" " -f $_.LinenUmber,$_.Line} 

Образец вывода:

PS> $cnt=0;gc .\test.txt |%{$cnt++;" " -f $cnt,$_} 1 foo 2 //approved 3 bar 4 // approved 5 foo 6 /* 7 approved 8 */ 9 bar 
1
Matt

catв PowerShell на самом деле псевдоним для Get-Content. Вы можете видеть это из Get-Alias cat. Многие из простых команд nix давали эквиваленты PS, чтобы облегчить пользователям переход в PowerShell. Они не идеальные зеркала, но они стараются.

Также нет необходимости выполнять какую-либо сложную работу с Get-Contentвыходными данными для расчета номеров строк. Это уже сделано для вас с помощью командлета.

Get-Content C:\temp\pingtst.csv | ForEach-Object{"$($_.readcount): $_"} 

Конечно, результат не идеален и выровнен по левому краю, но вы можете это исправить, свернув свои собственные функции и командлеты. PowerShell работает с максимальной производительностью с объектами, поэтому превращение вашего файла во что-то другое будет выглядеть так:

PS C:\Windows\system32> Get-Content C:\temp\pingtst.csv | Select-Object ReadCount,@}  ReadCount Line  --------- ----  1 localhost  2 localhost0 3 localhost1 4 localhost2 

Имейте в виду, что существует множество дополнительных параметров, например -Head, -Tailи -TotalCountт. Д., Которые могут добавить функциональность в этот, казалось бы, простой командлет.

Хотя я уверен, что это не совсем то, на что вы надеялись. Дело в том, Get-Contentчто номера строк уже известны, поэтому нет необходимости в подсчете или чем-то подобном.

1
Greenstone Walker
Get-Content -Path D:\in\demo.txt | % { " " -f $PSItem.Readcount, $PSItem } 

Или, возможно, следующее, чтобы гарантировать одну строку (в выводе PowerShell) на строку (в файле).

Get-Content -Path D:\in\demo.txt -ReadCount 1 | % { " " -f $PSItem.Readcount, $PSItem } 

Похожие вопросы