LoginSignup
2
5

More than 5 years have passed since last update.

PowerShell で awk の /pattern/,/pattern/ みたいなことをする

Posted at

相当するコマンドレットが思い当たらなかったので、以下のような関数を作りました。
同等のことができるコマンドレットがあれば教えてください。
あと関数の命名センスをください。

Select-Range.ps1
Function Select-Range {
    Param(
        [string]$Property, 
        [string]$Pattern1, 
        [string]$Pattern2
    )
    Begin {
        $flag = $False
    }
    Process {
        $Target = $_
        if ($Property) { $Target = $_.$Property }
        if ($Target -EQ $Null -OR $Target.GetType().FullName -NE "System.String") {
            Write-Error "Target Property is not System.String!"
            return
        }

        if(!$flag) { $flag = $Target -Match $Pattern1 }
        if($flag) { $_ } # output
        if($flag) { $flag = $Target -NotMatch $Pattern2 }
    }
}

使い方は以下のような感じで

使い方
PS> # 例えば以下のようなファイルがあったとして(Linux の sar -A です)
PS> Get-Content C:\Temp\20170611.txt

Linux 4.11.3-200.fc25.x86_64 (fedora25)         06/11/17        _x86_64_        (1 CPU)

13:26:39     LINUX RESTART      (1 CPU)

13:30:05        CPU      %usr     %nice      %sys   %iowait    %steal      %irq     %soft    %guest    %gnice     %idle
13:40:36        all      0.05      0.00      0.07      0.02      0.00      0.11      0.03      0.00      0.00     99.72
13:40:36          0      0.05      0.00      0.07      0.02      0.00      0.11      0.03      0.00      0.00     99.72
13:50:36        all      0.02      0.00      0.03      0.01      0.00      0.09      0.03      0.00      0.00     99.83
13:50:36          0      0.02      0.00      0.03      0.01      0.00      0.09      0.03      0.00      0.00     99.83
14:00:36        all      0.06      0.00      0.07      0.02      0.00      0.10      0.04      0.00      0.00     99.72
14:00:36          0      0.06      0.00      0.07      0.02      0.00      0.10      0.04      0.00      0.00     99.72
14:10:36        all      0.01      0.00      0.02      0.00      0.00      0.08      0.02      0.00      0.00     99.88
14:10:36          0      0.01      0.00      0.02      0.00      0.00      0.08      0.02      0.00      0.00     99.88
Average:        all      0.03      0.00      0.04      0.01      0.00      0.10      0.03      0.00      0.00     99.79
Average:          0      0.03      0.00      0.04      0.01      0.00      0.10      0.03      0.00      0.00     99.79

13:30:05       proc/s   cswch/s
13:40:36         0.14     46.97
13:50:36         0.04     35.14
14:00:36         0.07     42.10
14:10:36         0.03     29.48
Average:         0.07     38.53

13:30:05     pswpin/s pswpout/s
13:40:36         0.00      0.00
13:50:36         0.00      0.00
14:00:36         0.00      0.00
14:10:36         0.00      0.00
Average:         0.00      0.00

13:30:05     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
13:40:36         2.32      2.30     24.35      0.02     17.19      0.00      0.00      0.00      0.00
13:50:36         0.25      0.77      5.80      0.00      3.87      0.00      0.00      0.00      0.00
14:00:36         0.09      0.82     12.98      0.00      9.70      0.00      0.00      0.00      0.00
14:10:36         0.00      0.91      4.11      0.00      3.28      0.00      0.00      0.00      0.00
Average:         0.69      1.21     11.97      0.00      8.62      0.00      0.00      0.00      0.00

13:30:05          tps      rtps      wtps   bread/s   bwrtn/s
13:40:36         0.34      0.03      0.30      4.64      4.60
13:50:36         0.15      0.01      0.15      0.51      1.54
14:00:36         0.17      0.00      0.17      0.17      1.64
14:10:36         0.18      0.00      0.18      0.00      1.83
Average:         0.21      0.01      0.20      1.37      2.43

13:30:05      frmpg/s   bufpg/s   campg/s
13:40:36        -1.04      0.00      0.58
13:50:36        -0.09      0.00      0.07
14:00:36        -0.06      0.00      0.03
14:10:36        -0.03      0.00      0.00
Average:        -0.31      0.00      0.17

PS> 
PS> 
PS> 
PS> 
PS> # 以下のような感じで部分抽出ができます。
PS> # ひとつのファイルに複数のデータを混在させるの行儀悪いからやめて欲しい。
PS> Get-Content C:\Temp\20170611.txt | Select-Range -Pattern1 pgpgin -Pattern2 Average
13:30:05     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
13:40:36         2.32      2.30     24.35      0.02     17.19      0.00      0.00      0.00      0.00
13:50:36         0.25      0.77      5.80      0.00      3.87      0.00      0.00      0.00      0.00
14:00:36         0.09      0.82     12.98      0.00      9.70      0.00      0.00      0.00      0.00
14:10:36         0.00      0.91      4.11      0.00      3.28      0.00      0.00      0.00      0.00
Average:         0.69      1.21     11.97      0.00      8.62      0.00      0.00      0.00      0.00
PS> 
PS> 
PS> 
PS> 
PS> # ここまでできるとテキストの解析までやりたくなるので以下のようにしてデータ化します。
PS> Get-Content C:\Temp\20170611.txt | 
     Select-Range -Pattern1 pgpgin -Pattern2 Average | 
     % { $_ -replace "\s+","," } | 
     % {$index=1} { if($index -eq 1) { $_ = $_ -replace "^.{8}","Time" } $index++; $_ } | 
     select-string -NotMatch Average | 
     select -expand line | 
     convertfrom-csv | 
     % { $_.time = [datetime]$_.Time; $_ } | 
     ft

Time                pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
----                -------- --------- ------- -------- -------- --------- --------- --------- ------
2017/06/11 13:40:36 2.32     2.30      24.35   0.02     17.19    0.00      0.00      0.00      0.00
2017/06/11 13:50:36 0.25     0.77      5.80    0.00     3.87     0.00      0.00      0.00      0.00
2017/06/11 14:00:36 0.09     0.82      12.98   0.00     9.70     0.00      0.00      0.00      0.00
2017/06/11 14:10:36 0.00     0.91      4.11    0.00     3.28     0.00      0.00      0.00      0.00

PS> 
PS> 
PS> 
PS> 
PS> # このままだと [datetime] した時に、
PS> # 必ず作業当日になってしまうので、ファイル名から日付を取るようにしたい。
PS> $file = Get-Item "C:\Temp\20170611.txt"
PS> $date = $file.BaseName -replace "(....)(..)(..)","`$1/`$2/`$3 "
PS> Get-Content $file | 
     Select-Range -Pattern1 pgpgin -Pattern2 Average | 
     % { $_ -replace "\s+","," } | 
     % {$index=1} { if($index -eq 1) { $_ = $_ -replace "^.{8}","Time" } $index++; $_ } | 
     select-string -NotMatch Average | 
     select -expand line | 
     convertfrom-csv | 
     % { $_.time = [datetime]($date + $_.Time); $_ } | 
     ft

PS> # 出力は変化ないので省略

そういえば PowerShell は n 番目(大抵の場合 n=1 )のオブジェクトだけストリームの中で処理するという処理が手間ですね。

例えば、先ほど使用した以下のコマンドは、

% {$index=1} { if($index -eq 1) { $_ = $_ -replace "^.{8}","Time" } $index++; $_ }

Linux だと以下のように書けます。

sed -r '1s/^.{8}/Time/'

一回変数に入れれば良いという主張はその通りなのですが、シェル芸人的にはパイプの中で片付けたいところ。。。

誰かこんな感じの作ってくれないかなぁ
PS> get-content $file | Edit-Stream -Index 1 -Replace "^.{8}","Time"
2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5