Was ist das Äquivalent von Bashs cat -n in PowerShell?

3314
deostroll

Ich möchte cateine Datei und die Zeilennummer jeder Zeile ausgeben.

In PowerShell wird jedoch catein Array ausgegeben. Die Frage lautet also: Wie drucke ich den Index jedes Elements, während es auf der Konsole ausgegeben wird ...?

Ich habe so etwas ausprobiert:

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

Es hat mir einige seltsame Ergebnisse gebracht. Einige Zeilennummern wiederholt. Was ist ein eleganter und zuverlässiger Weg, dies zu tun?

7
"cat -n" ist eigentlich kein Teil von bash - es ist Teil von "cat", einem separaten Programm - und es gibt keinen Grund zu der Annahme, dass jede Maschine, auf der bash installiert ist, dies unterstützen wird. Charles Duffy vor 6 Jahren 4

7 Antworten auf die Frage

11
BartekB

Sie missbrauchen Select-String dafür möglicherweise:

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

Beispielausgabe:

LineNumber Line ---------- ---- 1 a  2  3 b  4  5 c  
cool deklarativer Code im Gegensatz zu den anderen Antworten cat vor 6 Jahren 0
5
DavidPostill

Ich möchte eine Datei katzen und die Zeilennummer jeder von ihr ausgegebenen Zeile ausgeben.

Verwenden Sie den folgenden Befehl:

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

In den Kommentaren wurde darauf hingewiesen:

  • Es kann besser sein zu verwenden, write-outputstatt, write-hostda dies ermöglicht die Weiterverarbeitung des Ausgangs.
  • echo ist ein Alias ​​für write-output

Der obige Befehl wird also:

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

Beispielausgabe:

> 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 > 

Beispielausgabe von Cygwin cat -nzum Vergleich:

$ cat -n test.txt 1 foo 2 //approved 3 bar 4 // approved 5 foo 6 /* 7 approved 8 */ 9 bar $ 
Hmmm ... Ja, ich denke das ist besser als meins. Ich könnte zwar den `Write-Host ...` in ` '-f $ counter, $ _` ändern (und ich kann immer noch nicht die Backticks dazu bringen, im Backticked-Text richtig zu funktionieren. ..) Jeff Zeitlin vor 6 Jahren 0
Write-Output wäre hier die bessere Wahl als Write-Host, wenn Sie die Daten zur Speicherung oder weiteren Verarbeitung an eine Pipeline senden möchten. Zoredache vor 6 Jahren 0
@Zoredache Sehr wahrscheinlich. Ich bin kein PowerShell-Experte :) DavidPostill vor 6 Jahren 0
@DavidPostill Standardmäßig ist es einfacher, "echo" (Aliasnamen für "Write-Output") zu verwenden. `Write-Host` ist ... besonders. Es ist, als würde man direkt in / dev / tty schreiben. Bob vor 6 Jahren 0
Danke für die Erklärung. Ich habe die Antwort aktualisiert. DavidPostill vor 6 Jahren 0
1
Jeff Zeitlin

IndexOf()stimmt mit dem ersten Vorkommen des Werts überein, sodass Ihre doppelten Zeilennummern, die Ihren ursprünglichen Code verwenden, bedeuten, dass Sie mehrere Zeilen in der Datei haben, die identisch sind. Versuche Folgendes:

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

Alles, woran Sie an der Eingabeaufforderung lange denken müssen, ist nicht elegant. Eleganz wäre also, genau das zu bekommen, was Sie brauchen, in ein Skript zu schreiben und das Skript bei Bedarf aufzurufen. Um dieses Problem auf elegante und kraftvolle Weise zu lösen, als ich es allein könnte, habe ich hier das Skript von Jeffrey Hicks verwendet: http://jdhitsolutions.com/blog/scripting/445/more-fun-with-get-numberedcontent/

Beispiel: Get-NumberedContent. \ README.txt Ausgabebeispiel:

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. 

Skript unten für den Fall, dass der Link fehlschlägt:

#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

Ähnlich dem Code von DavidPostill, jedoch mit einer rechtsbündigen Zahl wie cat -n

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

Oder mit dem gleichen Ergebnis:

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

Beispielausgabe:

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

catin PowerShell ist eigentlich ein Alias ​​für Get-Content. Sie können das von sehen Get-Alias cat. Viele der einfachen nix-Befehle gaben PS-Äquivalente an, um die Benutzer für PowerShell zu erleichtern. Sie sind keine perfekten Spiegel, aber sie versuchen es.

Es ist auch nicht nötig, die Fußnoten mit einer Get-ContentAusgabe zu berechnen, um die Zeilennummern zu berechnen. Das erledigt das Cmdlet bereits für Sie.

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

Zugegeben, die Ausgabe ist nicht perfekt und linksbündig ausgerichtet, aber Sie können dies beheben, indem Sie Ihre eigenen Funktionen und Cmdlets rollen. PowerShell arbeitet mit Objekten auf höchstem Niveau. Um Ihre Datei in etwas anderes zu verwandeln, würde dies folgendermaßen aussehen:

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

Denken Sie daran, es gibt eine Menge mehr Möglichkeiten zu helfen, wie -Head, -Tail, -TotalCountusw., die Funktionalität dieser scheinbar einfachen Cmdlets hinzufügen können.

Ich bin mir sicher, dass das nicht genau das ist, worauf Sie gehofft haben. Der Punkt ist, Get-Contentdass die Zeilennummern bereits bekannt sind, so dass keine Zählungen oder ähnliches erforderlich sind.

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

Oder vielleicht das Folgende, um eine Zeile (in der PowerShell-Ausgabe) pro Zeile (in der Datei) zu gewährleisten.

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