2017-01-30 18 views
0

一連の.txtファイル(正確には.hl7ファイルを検索するPowerShellスクリプトを作成しようとしていますが、これらのファイル内で4桁の数字が含まれているかどうかを調べることができます。ファイルに4桁の数字が含まれている場合は、元のファイル名の先頭に追加された文字列でファイルの名前を変更する必要があります。したがってtest.hl78000_test.hl7になります(ファイル内に4桁の数字が含まれている場合)。複数のファイルで文字列を検索し、その文字列でファイルの名前を変更します。

猛烈なグーグルでの一日を過ごした後や本サイトを通じて掘り、これは私が召集ことができる最高です:

$AccountIDs = ("8155", "8156", "8428") 
$Path = "C:\Users\ThatsMe\Downloads\messages" 
$Files = (Get-ChildItem $Path -Filter "*.hl7") 

for ($i = 0; $i -le $Files.Length; $i++) { 
    if (Get-Content $Files[$i].FullName | Select-String -Pattern $AccountIDs[$i]) { 
     Rename-Item $Files[$i].FullName -NewName (($AccountIDs[$i]) + "_" + $Files[$i].Name) 
    } 
} 

私はいくつかの興味深い結果を得ています。私は現在、4つのテストというメッセージフォルダ内のファイル、テストtest2はTEST3、およびskibbidybopを持っています。最初のもの、テストは、8156_testに正しく変更されます。ただし、他のファイルには触れません。私はテスト t検定へのファイル名を変更したときに今、スクリプトは完全にそのファイルをスキップして、それぞれ8156_test2(間違っていた)と8428_test3TEST2TEST3の名前を変更します。 skibbidybopは決して触られません。

そして、もちろん、PowerShellのからのエラーメッセージ:

Select-String : Cannot bind argument to parameter 'Pattern' because it is null. 
At line:6 char:61 
+ if (Get-Content $Files[$i].FullName | Select-String -Pattern <<<< $AccountIDs[$i]) { 
    + CategoryInfo   : InvalidData: (:) [Select-String], ParameterBindingValidationException 
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.SelectStringCommand 

Get-Content : Cannot bind argument to parameter 'Path' because it is null. 
At line:6 char:16 
+ if (Get-Content <<<< $Files[$i].FullName | Select-String -Pattern $AccountIDs[$i]) { 
    + CategoryInfo   : InvalidData: (:) [Get-Content], ParameterBindingValidationException 
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentCommand

更新されたコード

$Path = "C:\Users\ThatsMe\Downloads\messages" 

$pattern = '\b(8155|8156|8428)\b' 
Get-ChildItem $Path -Filter '*.hl7' | 
    Select-String -Pattern $pattern | 
    Group-Object Path | 
    ForEach-Object { 
     $id  = $_.Group.Matches[0].Groups[0].Value 
     $filename = $_.Group.Filename | Select-Object -First 1 
     Rename-Item -Path $_.Name -NewName "${id}_${filename}" -WhatIf 
    } 

これは私が今受信エラーです:

C:\> C:\Users\ThatsMe\Downloads\messages\changename.ps1 
Cannot index into a null array. 
At C:\Users\ThatsMe\Downloads\messages\changename.ps1:8 char:38 
+   $id  = $_.Group.Matches[ <<<< 0].Groups[0].Value 
    + CategoryInfo   : InvalidOperation: (0:Int32) [], RuntimeException 
    + FullyQualifiedErrorId : NullArray 

What if: Performing operation "Rename File" on Target "Item: 
C:\Users\ThatsMe\Downloads\messages\test.hl7 Destination: 
C:\Users\ThatsMe\Downloads\messages\_". 
Cannot index into a null array. 
At C:\Users\ThatsMe\Downloads\messages\changename.ps1:8 char:38 
+   $id  = $_.Group.Matches[ <<<< 0].Groups[0].Value 
    + CategoryInfo   : InvalidOperation: (0:Int32) [], RuntimeException 
    + FullyQualifiedErrorId : NullArray 

What if: Performing operation "Rename File" on Target "Item: 
C:\Users\ThatsMe\Downloads\messages\test3.hl7 Destination: 
C:\Users\ThatsMe\Downloads\messages\_".

答えて

3

あなたが得るエラーは、2つの間違いによって引き起こされます.1つは古典的なoff-by-one error。 PowerShellのアレイは、アレイの最後のインデックスは、その要素の数より1つ少ないことを意味し、ゼロベースれる:$iであるつつあなたforループが実行できる

[ 'a', 'b', 'c' ] → count == 3 
    0 1 2  → last index == 2 == 3-1

未満$Files.Length-lt ))、以下(-leない:

for ($i = 0; $i -lt $Files.Length; $i++) {

また、次の2つのdifferenに同じインデックス変数を使用することはできません両方の配列の長さが同じか少なくとも2番目の配列($AccountIDs)が最大のインデックス($Files)を決定するために使用されたものよりも多くの要素を持っていない限り、t配列$AccountIDsの要素数が$Filesより少ない場合、コードは最終的に$AccountIDsの上限を超えてインデックスにアクセスしようとします。また、おそらく$AccountIDsのすべての番号について各ファイルをチェックしたいと思うでしょう。そうするには、2番目のインデックス変数を持つ入れ子ループが必要です。


これは、必要以上に複雑にしているということです。あなたは、単にその正規表現と照合して確認することSelect-Stringにファイルのリストを単一regular expressionにあなたのIDを入れて配管することができます

$pattern = '\b(8155|8156|8428)\b' 
Get-ChildItem $Path -Filter '*.hl7' | 
    Select-String -Pattern $pattern | 
    Group-Object Path | 
    ForEach-Object { 
     $id  = $_.Group.Matches[0].Groups[0].Value 
     $filename = $_.Group.Filename | Select-Object -First 1 
     Rename-Item -Path $_.Name -NewName "${id}_${filename}" -WhatIf 
    } 

与えられた数字のいずれかに一致\b(8155|8156|8428)\b正規表現を。 \bは、81552や842893などの数字の一致を避けるために、単語の境界に一致を制限します。

Group-Objectステートメントは、名前が変更されたファイルの一意性を保証します(複数の一致が見つかった場合、ファイルの名前を複数変更することはありません)。

.Matches[0].Groups[0].Valueは、各ファイルの最初の一致の最初の取得グルー​​プの値を抽出します。

Select-Object -First 1は、ファイル内に複数の一致が見つかったとしても、ファイル名を持つ文字列が1つしか存在し、配列の配列ではないことを保証します。

-WhatIfスイッチを削除すると、名前変更操作が正しく機能することが確認され、実際にファイル名を変更するために文全体が再実行されます。


編集:あなたはそのバージョンがmember enumerationをサポートしていないので、少し扱いグループを調整する必要がV2 PowerShell用の

Get-ChildItem $Path -Filter '*.hl7' | 
    Select-String -Pattern $pattern | 
    Group-Object Path | 
    ForEach-Object { 
     $id  = $_.Group | Select-Object -Expand Matches -First 1 | 
        ForEach-Object { $_.Groups[0].Value } 
     $filename = $_.Group | Select-Object -Expand Filename -First 1 
     Rename-Item -Path $_.Name -NewName "${id}_${filename}" -WhatIf 
    } 
+0

あなたの答えは多くの視点に入り、私が間違っていた理由についての論理的な理由を理解する助けになりました。しかし、スクリプトを実行すると、次のエラーが表示されます。 'ヌル配列にインデックスできません。 C:... changename.ps1:8 char:38 + $ id = $ _。Group.Matches [<<<< 0] .Groups [0] .Value +カテゴリ情報:InvalidOperation:(0:Int32 )[]、RuntimeException + FullyQualifiedErrorId:NullArray' 「ファイルの名前の変更」操作を実行すると、「出力」の状態が発生します。スクリプトは正常に正しいファイルを見つけますが、それ以降はあまり効果がないようです。 – sabrobby

+0

投稿したコードで説明したエラーを再現することはできません。空のソースフォルダと、0,1、および1以上の一致を生成するファイルを持つソースフォルダでテストされます。 –

+0

ご協力いただきありがとうございます。実行しているPowerShellのバージョンで問題になるかもしれませんか? (バージョン2)。それにもかかわらず、私は先に進み、この質問を回答として提出する。 – sabrobby

関連する問題