とあるストレージ内のファイル一覧をファイル名[yyyymmdd.log]ログとして毎日取得し、  
本日と昨日のログを比べて、昨日ログにあって本日ログにない差分を抽出するプログラムを作りたいです！

ここで追加しようとして技術的に困っているのが  
昨日のログがなかったら、さらにその一日前のログをさかのぼって比べるを繰り返すプログラムです。

昨日と言うよりも、dirコマンドで新しい順に並べてその２番目とくらべてなかったら３番目とくらべる  
というようなプログラムでも良いと思います。

batファイル実行元としてパワーシェルかvbsを使ったとしても再現できるやり方ありましたらご教授いただけますとさいわいです。

* * *

**追記**

本日作られたログを除いた最新のログと比べたいです。 最新（本日）のログと昨日のログ(本日のログを除いた最新のログ)を比べたいのですが、条件として

  * 稼働初日で本日のログしかなかったらその場で、通常終了。
  * 事情があってサーバが停止などの理由で昨日のログがない場合、さらに前日のログを探しに行く。

のような条件をつけたいです。

現在のコードは

```

    set YYYYMMDD=%DATE:/=%
    
```

で当日日時取得

```

    for /F "tokens=1* delims=" %%a in ('dir /b /O:D C:\Users\user\Desktop\batdevelopment\logs*.log') do set zenjitu=%%a
    
```

でファイル内の最新ログ取得

```

    dir .txt /b > C:\Users\user\Desktop\batdevelopment\logs\%YYYYMMDD%.log
    
```

で本日ログ掃き出し

```

    powershell -c "compare (cat ./%zenjitu%.txt) (cat ./%YYYYMMDD%.log) | ? {$_.SideIndicator -eq '<='} | ft -Property InputObject -hide"
    
```

で差分出力。

この時、下記のコードにオプションを追加して、フォルダ内の最新のファイル名を除外した、その次の最新ファイルを取得したいです。

```

    for /F "tokens=1 delims=" %%a in ('dir /b /O:D C:\Users\user\Desktop\batdevelopment\logs*.log') do set zenjitu=%%a
    
```
CC BY-SA 4.0
2019-11-30T01:50:14.170
60951
2019-12-01T18:25:39.953
2019-12-01T06:28:43.163
7347
36855
question
powershell batch-file
batで毎日ログをとって比べるプログラムを作りたいです。
要件を正しく把握できているかわかりませんが、PowerShellだと以下のようになります。  
今日のログファイルと今日以外のログファイルの中で最新のファイルとを比較しています。

```

    # ログファイルがあるフォルダ
    $logDir = "C:\Users\user\Desktop\batdevelopment\logs"
    
    # 今日のログファイル名
    $logFileNameToday = "{0:yyyyMMdd}.log" -f [datetime]::Now
    
    # 今日のログ取得
    $logToday = Get-Content "$logDir\$logFileNameToday"
    
    # 差分出力
    Get-ChildItem "$logDir\*" -Filter *.log -Exclude $logFileNameToday | select -Last 1 | Get-Content | where { $_ -notin $logToday }
    
```

最後の行だけをざっと説明すると

  1. `Get-ChileItem -Exclude <今日のログファイル名>` で今日のログファイルを除外。
  2. `Select-Objec -Last 1`でその中で最新のファイルを抽出。
  3. `Get-Content`でその内容を取得。
  4. `Where-Object { $_ -notin <今日のログデータの配列> }` で今日のログに含まれないものを抽出。

という流れです。  
`Compare-Object`はいい方法ですがスクリプト中では少し使いづらいコマンドレットなのでここでは`Where-Object`で抽出しています。

バッチファイル中で使えるように圧縮して書くと次のようになります。

```

    set LOGDIR="C:\Users\user\Desktop\batdevelopment\logs"
    set TODAYLOG="%DATE:/=%.log"
    powershell -c "$t=gc \"%LOGDIR%\\%TODAYLOG%\"; ls "%LOGDIR%\\*\" *.log -e %TODAYLOG%|select -l 1|gc|?{$_-notin$t}"
    
```
CC BY-SA 4.0
2019-12-01T06:39:39.877
60982
2019-12-01T15:47:06.720
2019-12-01T15:47:06.720
28280
28280
60951
answer
> 技術的に困っているのが 昨日のログがなかったら、さらにその一日前のログをさかのぼって比べるを繰り返すプログラムです。

苦労して シェルで作るより C# で作るとサクッと作れたので検討ください。  
`dotnet Core 3.0` をインストールして

gitdirname.bat

```

    @echo off
    pushd
    rem getname.bat ログディレクトリ名
    cd /d %~dp0
    dotnet run %1
    popd
    
```

`dotnet new console` して Program.cs の内容

```

    using System;
    
    namespace getLog
    {
        class Program
        {
            static void Main(string[] args)
            {
                String todayDir = DateTime.Today.ToString("yyyyMMdd");
                if (args.Length == 0) {
                    Console.WriteLine(todayDir);
                    return;
                }
    
                string dir = args[0];
                // 前日のログファイル見つかるまで ログを探す（最大1年とする）
                for(DateTime tm = DateTime.Today.AddDays(-1); tm > DateTime.Today.AddYears(-1); tm = tm.AddDays(-1)) {
                    String todayLogFileName = tm.ToString("yyyyMMdd") + ".log";
    
                    if (System.IO.File.Exists(System.IO.Path.Combine(dir , todayLogFileName))) {
                        Console.WriteLine(todayLogFileName);
                        return;
                    }
                }
    
                // 見つからなければ 今日のファイル名を利用する
                Console.WriteLine(todayDir);
                return;
    
            }
        }
    }
    
    
```

最後に 実行結果を環境変数に入れる部分

```

    for /F "tokens=1 delims=" %a in ('cmd /c アプリのディレクトリ名\gitname.bat') do set PREV_YYYYMMDD=%a
    
```
CC BY-SA 4.0
2019-12-01T18:25:39.953
60995
2019-12-01T18:25:39.953
18851
60951
answer