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

質問
-
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を出力する方法について教えていただけませんでしょうか。
初歩的なことで申し訳ありませんが,よろしくお願いします。
すべての返信
-
隣合うファイル同士で繰り返し連続処理
$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
-
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
-
例えば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"
になりますね。
- 編集済み Hongliang 2019年8月14日 14:33
- 回答の候補に設定 flingminMicrosoft contingent staff, Moderator 2019年8月27日 7:39
-
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
-
Import-Csv ["data." +$i].csv
の部分を
Import-Csv ($("data"+$i)+".csv")
に変更
- 回答の候補に設定 flingminMicrosoft contingent staff, Moderator 2019年8月27日 7:38
-
チキンさま
ご回答ありがとうございます。ご指摘の通り修正したところ,エラーが出なくなりました。
しかし,ファイルが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")
}
よろしくお願いいたします。
-
Forループでも$iをインクリメントしていて、ファイル名指定の部分でもインクリメントしているので、
1回のループで2回インクリメントされているのが原因だと思われます。ファイル名の部分をインクリメントではなく明示的に+1としてみてください。
- 回答の候補に設定 flingminMicrosoft contingent staff, Moderator 2019年8月27日 7:38
-
チキンさま,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
-
こんにちは
フォーラムを通して問題が解決できたとのことで、よかったです。
チキンさんと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