ファイルをcat
して、出力する各行の行番号を出力したい。
ただし、PowerShellでは、cat
は配列を出力します。したがって、問題は効果的になります。コンソールに出力されている間に、各項目のインデックスを印刷するにはどうすればよいですか?
私はこのようなものを試しました:
$k = cat foo.js
$k | foreach { $index = $k.IndexOf($_) + 1; write "$index : $_"; } | more
それは私にいくつかの奇妙な結果を与えました。一部の行番号が繰り返されています。これを行うためのエレガントでより信頼できる方法は何ですか?
次のコマンドを使用します。
$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
$
そのためにSelect-Stringを乱用する可能性があります。
Select-String -Pattern .* -Path .\foo.txt | select LineNumber, Line
出力例:
LineNumber Line
---------- ----
1 a
2
3 b
4
5 c
IndexOf()
はfirstの値の出現と一致するため、元のコードを使用して重複する行番号は、ファイル内に同一の複数の行があることを意味します。以下を試してください:
$k = Get-Content -Path foo.js
$l = 0
while ($l -lt $k.length) {
"{0,5}: {1}" -f $l,$k[$l]
$l++
}
プロンプトで長く考えなければならないことはエレガントではありません。したがって、エレガンスとは、必要なものを正確に取得し、スクリプトに入れて、必要なときにスクリプトを呼び出すことです。この正確な問題を自分でよりもエレガントかつ強力に解決するために、ここでJeffrey Hicksスクリプトを使用しました: 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 "No blank lines"}
Write-Debug "Comment character is #CommentCharacter"
Write-Debug "Comment color is $CommentColor"
if ($passthru) {Write-Debug "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 = "{0:d$($c)} | {1}" -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 = "{0:d$($c)} | {1}" -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
DavidPostillのコードに似ていますが、cat -nのように右揃えされます。
$cnt=0;gc .\test.txt|%{$cnt++;"{0,6} {1}" -f $cnt,$_}
または同じ結果:
select-string -path .\test.txt "^" |%{"{0,6} {1}" -f $_.LinenUmber,$_.Line}
出力例:
PS> $cnt=0;gc .\test.txt |%{$cnt++;"{0,6} {1}" -f $cnt,$_}
1 foo
2 //approved
3 bar
4 // approved
5 foo
6 /*
7 approved
8 */
9 bar
PowerShellのcat
は、実際にはGet-Content
のエイリアスです。これはGet-Alias cat
から確認できます。単純なnixコマンドの多くは、ユーザーがPowerShellを使いやすくするためにPSと同等のものを提供していました。彼らは完璧な鏡ではありませんが、試します。
また、行番号を計算するために 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,@{Name="Line";Expression={"$_"}}
ReadCount Line
--------- ----
1 localhost
2 localhost0
3 localhost1
4 localhost2
この一見単純なコマンドレットに機能を追加できる-Head
、-Tail
、-TotalCount
などのような、さらに多くのオプションがロードされることに注意してください。
それはあなたが望んでいたこととは全く違うと確信していますが。ポイントは、Get-Content
はすでに行番号を知っているので、カウントなどは必要ないということです。
Get-Content -Path D:\in\demo.txt | % { "{0,5} {1}" -f $PSItem.Readcount, $PSItem }
または、おそらく次のようにして、(ファイル内の)行ごとに(PowerShell出力内の)1行を保証します。
Get-Content -Path D:\in\demo.txt -ReadCount 1 | % { "{0,5} {1}" -f $PSItem.Readcount, $PSItem }