[PS1]「シェル・ワンライナー 160 本ノック」第1章を Powershell でやってみた

2023年2月25日

 「PowerShellワンライナーで解く『シェル・ワンライナー160本ノック』第1章」という記事をみたので、つられてやってみました(ぇ

 書籍情報はここ。問題自体は書籍を参照してください。
 問題に使われているデータはこちらで提供されています。

 また、このページではワンライナーを「改行がないこと」「複文としないこと(";" で区切らないこと)」とします。(一般的な定義がどうだかは知りません)
 そのうえで、個人的にワンライナーは好きではないので、以下の解は基本的にワンライナーで書いていません(汗 普通に改行やインデントを使用しています。

  1. 問1

     正規表現で Match させた例。

    gc .\files.txt |
    ? {
        $_ -match "\.exe$"
    }
    

     拡張子を求めて比較した例。

    gc .\files.txt |
    ? {
        [System.IO.Path]::GetExtension($_) -eq ".exe"
    }
    
  2. 問2

    Add-Type -AssemblyName System.Drawing
    gci *.jpg |
    % {
        $image = [System.Drawing.Image]::FromFile($_.fullname)
        $newname = [System.IO.Path]::ChangeExtension($_.fullname, "png")
        $image.Save($newname, [System.Drawing.Imaging.ImageFormat]::Png)
    }
    

     下記は、上記の変数部分を展開し、ワンライナーにしてみた例です。(";" を使わない例/改行は読みにくくなるので削っていませんが、削っても動きます。ただし、Add-Type の行はどうもならないのでここだけは ";" で区切っています。)
     問11 の例を除いて、このページの解答例は、同様の手法(変数部分の展開や;区切り、文字列の連結など)でワンライナーにすることができます。

    Add-Type -AssemblyName System.Drawing;
    gci *.jpg |
    % {
        [System.Drawing.Image]::FromFile($_.fullname).Save([System.IO.Path]::ChangeExtension($_.fullname, "png"), [System.Drawing.Imaging.ImageFormat]::Png)
    }
    
  3. 問3

     書式を "0000" とした例。

    gci |
    % {
        $newname = "{0:0000}" -f [int]$_.Name
        ren $_ $newname
    }
    

     書式を "D4"(桁数を数値で指定)とした例。

    gci |
    % {
        $newname = "{0:D4}" -f [int]$_.Name
        ren $_ $newname
    }
    
  4. 問4
    gci |
    ? {
        [int](gc -raw $_) -eq 10
    } | 
    % {
        del $_
    }
    
  5. 問5
    gc .\ntp.conf | 
    % {
        if ($_ -match "^pool (.+ )") {
            $Matches[1]
        }
    } 
    
  6. 問6

     スペースの数を書式で指定した例。

    @(5..1) |
    % {
        "{0,$_}" -f "x"
    }
    
  7. 問7

     1.1 や 1.08 は二進小数(= 浮動小数点型)では無限小数となるので、Decimal を使用しています。

     あと、-split した配列を "," 演算子を使用して配列のままパイプに流しています。

    (
        gc .\kakeibo.txt | 
        % {
            ,($_ -split " ")
        } |
        % {
            if ($_[1] -match "\*" -or $_[0] -lt "20191001") {
                [decimal]$_[2] * 1.08d
            } else {
                [decimal]$_[2] * 1.1d
            }
        } |
        Measure -Sum
    ).Sum
    
  8. 問8

     時刻文字列が年と時の間に ":" が入っているので、[DateTime]::ParseExact を使用し、時刻の書式を指定しています。

     ちなみに夜の 12 時 (AM12 時)、昼の 12 時 (PM12 時)はともに午前です(ぇ
     参考「質問4-1)正午は午前12時?それとも、午後12時?

    gc .\access.log |
    % {
        if ($_ -match "\[(.+)\]$") {
    
            $date = [DateTime]::ParseExact($Matches[1],"dd/MMM/yyyy:HH:mm:ss zzz",[System.Globalization.CultureInfo]::InvariantCulture)
    
            if ($date.Hour -le 12) {
                "午前"
            } else {
                "午後"
            }
        }
    } |
    group |
    select Name, Count
    
  9. 問9

     時刻文字列が年と時の間に ":" が入っていない一般的な形式なので、Get-Date -Date を使用し、時刻の書式は指定していません。

    gc .\log_range.log |
    ? {
        if ($_ -match "\[(.+)\]") {
            $from = Get-Date -Date "2016/12/24 21:00:00"
            $to = Get-Date -Date "2016/12/25 4:00:00"
            $date = Get-Date -Date $Matches[1]
    
            ($from -le $date) -and ($date -lt $to)
        }
    }
    
  10. 問10
    gc .\headings.md |
    % {
        if ($_ -match "# (.+)$") {
            $Matches[1]
            "==="
    
        } elseif ($_ -match "## (.+)$") {
            $Matches[1]
            "---"
    
        } else {
            $_
    
        } 
    }
    
  11. 問11

     この例は唯一ワンライナーに書き換えることができません。

    $names = @{};
    $names["すず"] = "鈴木";
    $names["さと"] = "佐藤";
    $names["やま"] = "山本";
    
    $gijiroku = gc .\gijiroku.txt;
    
    for ($i = 0; $i -lt $gijiroku.Length; $i += 3)
    {
        $name = $gijiroku[$i]
        $text = $gijiroku[$i + 1]
        "{0}: {1}`n" -f $names[$name], $text
    }
    

     ワンライナーにこだわるなら以下のようにも書けますし、ある意味上記よりこちらのほうがシンプルではあります。
     しかし個人的に読解性/メンテ性の観点から好きではありません。

    gc -Raw .\gijiroku.txt |
    % {$_ -replace "(^|`r?`n)さと`r?`n","`n佐藤:"} |
    % {$_ -replace "(^|`r?`n)すず`r?`n","`n鈴木:"} |
    % {$_ -replace "(^|`r?`n)やま`r?`n","`n山本:"}
    





カテゴリー: PowerShell

Follow comments via the RSS Feed | Leave a comment | Trackback URL

コメントを投稿する

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


«  
 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org