windows上命令行@文件内容查看方案@行号显示@nlps@cat -n

abstract

windows上命令行@文件内容查看@行号显示@nlps@cat -n

本文给出的powershell函数(Get-ContentNL)支持管道符输入,文件名(数组)或者字符串本身都可以传入进行计数和内容显示

可以配合ls等命令传递需要查看的文件给Get-ContentNL,可以灵活使用

refs

windows的cat -n(查看文件并显示行号)

powershell:使用循环实现

  • 方案1:

    • 	 
      # 关键在于格式化'{0,5} {1}' -f
        Get-Content $FileName | ForEach-Object { '{0,-5} {1}' -f $_.ReadCount, $_ }
      
  • 或者:

    • $file="file.ext"; $counter = 0; get-content $file  | % { $counter++; echo "`t$counter` $_" }
      
  • 其中%foreach-object的别名

    • PS D:\repos\blogs> gal %|fl
      
      DisplayName       : % -> ForEach-Object
      CommandType       : Alias
      Definition        : ForEach-Object
      ReferencedCommand : ForEach-Object
      ResolvedCommand   : ForEach-Object
      

powershell:编写成函数命令调用👺

function Get-ContentNL
{
    <# 
.SYNOPSIS
该函数用于计数地输出文本内容:在每行的开头显示该行是文本中的第几行(行号),以及该行的内容
支持管道符输入被统计对象
#>
    <# 
.EXAMPLE
#常规用法,通过参数指定文本文件路径来计数地输出文本内容
Get-ContentNL -InputData .\r.txt
.EXAMPLE
rvpa .\r.txt |Get-ContentNL
.EXAMPLE
将一个三行的文本字符串作为管道输入,然后将其,显式指出将管道符内容视为字符串而不是路径字符串进行统计
#创建测试多行字符串变量
$mlstr=@'
line1
line2
line3
'@

$mlstr|Get-ContentNL -AsString

.EXAMPLE
计数一个多行字符串变量的行数
PS C:\repos\scripts\PS\Test> $mlstr=@'
>> line1
>> line2
>> line3
>> '@
PS C:\repos\scripts\PS\Test> $mlstr
line1
line2
line3
PS C:\repos\scripts\PS\Test> Get-ContentNL -InputData $mlstr -AsString
1:line1
2:line2
3:line3
.EXAMPLE
#跟踪文本文件内容的变化(每秒刷新一次内容);
Get-ContentNL -InputData .\log.txt -RepetitionInterval 1
.EXAMPLE
#在powershell新窗口中更新
Start-Process powershell -ArgumentList '-NoExit -Command Get-ContentNL -InputData .\log.txt -RepetitionInterval 1'
.EXAMPLE
ls传递给cat读取合并,然后在传给Get-ContentNL来计数处理

PS> ls ab*.cpp|cat|Get-ContentNL -AsString -Verbose
VERBOSE: Checking contents...
1:#include <iostream>
2:using namespace std;
3:int main()
4:{
5:
6:    int a, b, c;
7:    cin >> a >> b;
8:    c = a + b;
9:    cout << c << endl;
10:    return 0;
11:}
12:#include <iostream>
13:using namespace std;
14:int main()
15:{
16:
17:
18:    int a, b, c;
19:    cin >> a >> b >> c;
20:    cout << (a + b) * c << endl;
21:    return 0;
22:}
VERBOSE: 2024/9/14 22:03:43
 
.EXAMPLE
#从ls命令通过管道符传递多个文件进行读取
PS🌙[BAT:79%][MEM:48.16% (15.27/31.71)GB][22:03:52]
# [cxxu@CXXUCOLORFUL][<W:192.168.1.178>][C:\repos\scripts\Cpp\stars_printer]
PS> ls ab*.cpp|Get-ContentNL
# Start File(1) [C:\repos\scripts\Cpp\stars_printer\ab.cpp]:

1:#include <iostream>
2:using namespace std;
3:int main()
4:{
5:
6:    int a, b, c;
7:    cin >> a >> b;
8:    c = a + b;
9:    cout << c << endl;
10:    return 0;
11:}

# End File(1) [C:\repos\scripts\Cpp\stars_printer\ab.cpp]:

# Start File(2) [C:\repos\scripts\Cpp\stars_printer\abc.cpp]:

1:#include <iostream>
2:using namespace std;
3:int main()
4:{
5:
6:
7:    int a, b, c;
8:    cin >> a >> b >> c;
9:    cout << (a + b) * c << endl;
10:    return 0;
11:}

# End File(2) [C:\repos\scripts\Cpp\stars_printer\abc.cpp]:

.EXAMPLE
通过get-item命令(别名gi)获取字符串对应的文件
PS🌙[BAT:79%][MEM:48.52% (15.39/31.71)GB][22:04:07]
# [cxxu@CXXUCOLORFUL][<W:192.168.1.178>][C:\repos\scripts\Cpp\stars_printer]
PS> gi .\ab.cpp|Get-ContentNL
# Start File(1) [C:\repos\scripts\Cpp\stars_printer\ab.cpp]:

1:#include <iostream>
2:using namespace std;
3:int main()
4:{
5:
6:    int a, b, c;
7:    cin >> a >> b;
8:    c = a + b;
9:    cout << c << endl;
10:    return 0;
11:}

# End File(1) [C:\repos\scripts\Cpp\stars_printer\ab.cpp]:

.Notes
可以设置别名,比如pscatn,psnl
#>
    [CmdletBinding()]
    param(
        # 可以是一个表示文件路径的字符串,也可以是一个需要被统计行数并显示内容的字符串;后者需要追加 -AsString 选项
        [Parameter(
            Mandatory = $false, #这里如果使用这个参数的话,必须要指定非空值,为了增强兼容性,不适用改参数,或者指定为$false
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        # [string]
        [Alias('InputObject')]$InputData,
        
        # [Parameter(ParameterSetName = 'FilePath')]
        # [switch]$AsFilePath,

        # [Parameter(ParameterSetName = 'String')]
        [switch]$AsString,
        # 定时刷新查看文件内容的间隔时间(秒),0表示一次性查看
        $RepetitionInterval = 0,
        [switch]$Clear,
        $LineSeparator = '#'
        # [switch]$NewShell #todo

    )

    begin
    {
        Write-Verbose 'Checking contents...'
        $itemNumber = 1
        $lineNumber = 0 #为了支持列表输入,对多个文件分别计数,此变量放到process块中
    }

    process
    {
        
        
        if ($AsString)
        # if ($PSCmdlet.ParameterSetName -eq 'String')
        {
            # 如果是字符串,则认为是直接传入的文件内容
            $InputData -split "`n" | ForEach-Object {
                $lineNumber++
                "${lineNumber}:$_"
            }
        }
        else
        {
            # 否则,认为是文件路径,但是还是要检查文件是否存在或者合法
            if(!(Test-Path $InputData -PathType Leaf)){
                Write-Error "File does not exist:$($InputData.Trim()) Do you want to consider the Input as a string?(use -AsString option ) "
                return
            }
            $lineNumber = 0

            Write-Host "$LineSeparator Start File($itemNumber) [$_]" -BackgroundColor Yellow -NoNewline
            Write-Host "`n"
            
            try
            {
                if (Test-Path $InputData -PathType Leaf)
                {
                    Get-Content $InputData | ForEach-Object {
                        $lineNumber++
                        "${lineNumber}:$_"
                    }
                }
                else
                {
                    Write-Error "File does not exist: $InputData"
                }
            }
            catch
            {
                Write-Error "An error occurred: $_"
            }

            Write-Host ''
            Write-Host "$LineSeparator End File($itemNumber) [$_]:"-BackgroundColor Blue -NoNewline
            Write-Host "`n"
            $itemNumber++

        }
        # 定时刷新查看指定文件内容
        if ($RepetitionInterval)
        {
            
            while (1)
            {
                # 清空屏幕(上一轮的内容会被覆盖)
                if ($Clear) { Clear-Host }

                # 这里使用递归调用(并且将此处调用的RepetitionInterval指定为不刷新(0),否则嵌套停不下来了)
                Get-ContentNL -InputData $InputData -RepetitionInterval 0
                # 也可以简单使用 
                # Get-Content $InputData
                Start-Sleep $RepetitionInterval
            }

        }
     

    }
    end
    {
        Write-Verbose (Get-DateTime)
    }
}

取别名,例如取为nlps,或者干脆把函数名设置为nlpscatn等缩写形式

Set-Alias -Name nlps -Value Get-ContentNL

用例

  • 此版本支持管道符的用法(更多用例详见函数定义内部的注释文档)
PS>  ipconfig|select -Index (20..25)|nlps -AsString
1:   IPv4 地址 . . . . . . . . . . . . : 192.168.1.77
2:   子网掩码  . . . . . . . . . . . . : 255.255.255.0
3:   默认网关. . . . . . . . . . . . . : fe80::1%18
4:                                       192.168.1.1
5:
6:以太网适配器 蓝牙网络连接:

FAQ

文件编码问题@(中文乱码)

  • 通常,如果你的文本文件使用文字软件可以正确识读,但是使用cat(即get-content)却出现了乱码

  • 这在某些国人编写的脚本文件中经常出现,比如批处理文件.bat里面的中文字符可能是GBKGB2312编码

  • powrshell的cat命令,默认用的流行编码utf8

  • 这可能导致文本无法正常识读,您可以考虑修改cat的默认解读编码,通过-encoding选项指定为GB2312或者GBK再试一次

使用第三方工具👺

posted @ 2022-03-08 16:05  xuchaoxin1375  阅读(34)  评论(0)    收藏  举报  来源