none
PowerShellにて複数ファイルを繰り返し連続処理する方法について RRS feed

  • 質問

  • PowerShellで複数ファイルを繰り返し連続処理する方法について教えてください。

    連続する複数のcsvファイル

    data1.csv

    data2.csv

    data3.csv

    ・・・

    があり,それぞれのファイルには

    (列1,列2)=(ID, Age)=(A,a),(B,b),(C,c)…

    の形でデータがあります。そして

    data1とdata2のIDを比較し,data1にあってdata2にないIDに対応するAgeを出力します。

    この処理をdata1とdata2,data2とdata3…と次のファイル同士で繰り返し行いたいと思っています。

    この中で,隣合うファイル同士で繰り返し連続処理を行う方法とIDに対応するAgeを出力する方法について教えていただけませんでしょうか。

    初歩的なことで申し訳ありませんが,よろしくお願いします。

    2019年8月14日 10:14

すべての返信

  • 隣合うファイル同士で繰り返し連続処理

    $prev = $null foreach ($file in $files) { $curr = ... # $fileから読み取る if ($prev) { # $prevと$currを使ってなんやかんやする } $prev = $curr }

    IDに対応するAgeを出力する方法

    これはちょっと何を疑問に持たれたのかわかりませんでした。

    その他

    csvの読み取りにはImport-Csvコマンドレットを使用すれば簡単です。

    また、差集合を取るには Compare-Object を使用できます。

    Compare-Object $集合1 $集合2 -Property id -PassThru |
        Where-Object -Property SideIndicator "<="

    まずCompare-Objectコマンドレットにより、idというプロパティで2つの集合が比較され、どちらかにしか含まれていないオブジェクトがパイプに流れます。

    次にWhere-Objectコマンドレットにより、SideIndicatorというプロパティが"<="であるもの、すなわち左側(集合1)に含まれていて右側(集合2)には含まれていないオブジェクトだけが次のパイプに流れます。SideIndicatorは元々のオブジェクトには含まれませんが、Compare-Objectがパイプに流す際に追加してくれています。



    • 編集済み Hongliang 2019年8月14日 12:09
    2019年8月14日 11:54
  • Hongliangさま

    ご回答ありがとうございます。質問がわかりにくくて申し訳ありません。

    見よう見まねで作成してみました。

    Ageを出力する方法について

    例えばdata.0.csv,data.1.csvのIDを比較して出力する場合,以下ではIDしか出力されません。IDに対応するAgeも出力したいのですがどのように変更すればよろしいでしょうか。

    $a = Import-Csv data.0.csv

    $b = Import-Csv data.1.csv

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties | foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

    }

    }

    $a_only | select * -ExcludeProperty SideIndicator| Export-Csv  -Path A0.csv

    複数ファイルを連続処理する方法について

    上記方法では(data.0, data.1)しか比較できません。これを(data.1, data.2),(data.2, data.3) … と連続処理したいと思っています。以下のように変更してみたのですが,エラーが出てしまいます。どのような修正が必要か教えていただけませんでしょうか。

    for ( $i = 1; $i -lt 10; $i++ )

    {

    $a = Import-Csv ["data" +$i].csv

    $b = Import-Csv ["data" +$i+1].csv

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties | foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

        }

    }

    $a_only | select * -ExcludeProperty SideIndicator | Export-Csv -NoTypeInformation -Path ["A" +$i].csv

    }


    • 編集済み U_obakec 2019年8月14日 14:30
    2019年8月14日 13:22
  • 例えばdata.0.csv,data.1.csvのIDを比較して出力する場合,以下ではIDしか出力されません。IDに対応するAgeも出力したいのですがどのように変更すればよろしいでしょうか。

    Compare-Objectに-PassThruパラメータを指定すれば、-Propertyで指定したプロパティだけでなく、もともとのオブジェクトがパイプに流されるようになります(-PassThruでも、先述のようにSideIndicatorは付加されます)。

    複数ファイルを連続処理する方法について

    上記方法では(data.0, data.1)しか比較できません。これを(data.1, data.2),(data.2, data.3) … と連続処理したいと思っています。以下のように変更してみたのですが,エラーが出てしまいます。

    エラーが出るなら、そのエラーの内容を書いてください。できればコピー&ペーストで。(ファイルパスに人名が含まれてないかなどは確認してください)

    とりあえずちらっと見た感じ、 "data" + $i + 1 だと、左から演算されるので、$i が 1 の場合だと

    "data" + $i → "data1"

    "data1" + 1 → "data11"

    になりますね。

    2019年8月14日 14:32
  • Hongliangさま

    ご回答ありがとうございます。-PassThruを付け加えることでAgeも出力することができました。

    $a = Import-Csv data.0.csv

    $b = Import-Csv data.1.csv

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties -PassThru| foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

    }

    }

    $a_only| select * -ExcludeProperty SideIndicator | Export-Csv -NoTypeInformation -Path A1.csv

    複数ファイルの連続処理について

    以下のように$i++に変更してみました。

    for ( $i = 0; $i -lt 1; $i++)

    {

    $a = Import-Csv ["data." +$i].csv

    $b = Import-Csv ["data." +$i++].csv

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties -PassThru| foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

    }

    }

    $a_only | select * -ExcludeProperty SideIndicator | Export-Csv -NoTypeInformation -Path ["A" +$i].csv

    }

    実行してみたのですが,以下のようなエラーが出てしまいます。ファイル名を指定する箇所に問題があるのでしょうか。

    Import-Csv : Cannot bind parameter 'Delimiter'. Cannot convert value "+0].csv" to type "System.Char". Error: "String must be exactly one character long."

    At line:4 char:26

    + $a = Import-Csv ["data." +$i].csv

    +                          ~~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Import-Csv], ParameterBindingException

    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.ImportCsvCommand

     

    Import-Csv : Cannot bind parameter 'Delimiter'. Cannot convert value "+0++].csv" to type "System.Char". Error: "String must be exactly one character long."

    At line:5 char:26

    + $b = Import-Csv ["data." +$i++].csv

    +                          ~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Import-Csv], ParameterBindingException

    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.ImportCsvCommand

     

    Export-Csv : Cannot bind parameter 'Delimiter'. Cannot convert value "+0].csv" to type "System.Char". Error: "String must be exactly one character long."

    At line:17 char:94

    + ... rty SideIndicator | Export-Csv -NoTypeInformation -Path ["A" +$i].csv

    +                                                                  ~~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Export-Csv], ParameterBindingException

    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.ExportCsvCommand

    よろしくお願いいたします。


    • 編集済み U_obakec 2019年8月14日 17:36
    2019年8月14日 17:35
  • Import-Csv ["data." +$i].csv

    の部分を

    Import-Csv ($("data"+$i)+".csv")

    に変更

    2019年8月15日 0:05
  • チキンさま

    ご回答ありがとうございます。ご指摘の通り修正したところ,エラーが出なくなりました。

    しかし,ファイルがA1,A3,A5…と飛び飛びになっていて,比較結果も出力されていません。

    ファイル指定部分に修正が必要でしょうか。

    for ( $i = 0; $i -lt 10; $i++)

    {

    $a = Import-Csv ($("data" +$i)+".csv")

    $b = Import-Csv ($("data" +$i++)+".csv")

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties -PassThru| foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

    }

    }

    $a_only | select * -ExcludeProperty SideIndicator | Export-Csv -NoTypeInformation -Path ($("A" +$i)+".csv")

    }

    よろしくお願いいたします。

    2019年8月15日 0:37
  • Forループでも$iをインクリメントしていて、ファイル名指定の部分でもインクリメントしているので、
    1回のループで2回インクリメントされているのが原因だと思われます。

    ファイル名の部分をインクリメントではなく明示的に+1としてみてください。

    2019年8月15日 0:50
  • チキンさま,Hongliangさま

    ご回答ありがとうございます。ご指摘の通り,$l=$i+1を以下のように加えたところ,正しく出力することができました。

    拙い質問にも関わらず,ご指導いただきありがとうございました。

    for ( $i = 0; $i -lt 5; $i++)

    {

    $a = Import-Csv ($("data" +$i)+".csv")

    $l=$i+1

    $b = Import-Csv ($("data" +$l)+".csv")

    $a_only = $b_only = @()

    $properties = "ID"

    Compare-Object $a $b -Property $properties -PassThru| foreach {

        if($_.SideIndicator -eq "<=")

        {

            $a_only += $_

    }

    }

    $a_only | select * -ExcludeProperty SideIndicator | Export-Csv -NoTypeInformation -Path ($("A" +$i)+".csv")

    }


    • 編集済み U_obakec 2019年8月15日 1:17
    2019年8月15日 1:16
  • こんにちは

    フォーラムを通して問題が解決できたとのことで、よかったです。

    チキンさんとHongliangさんも、適格なアドバイスをいただきありがとうございました。

    同じ問題を持っている人々に役に立つために、参考になった投稿には「回答としてマーク」をご設定ください。

    今後ご不明な点がございましたら、お気軽にお問い合わせください

    FAN


    Please remember to mark the replies as an answers if they help. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com

    2019年8月27日 7:43
    モデレータ