Windows:ファイルの正規表現を使用したファイルのコピー/移動?


10

私は基本的に実行したいです

C:\>xcopy [0-9]{13}\.(gif|jpg|png) s:\TargetFolder /s

xcopyは正規表現のファイル名検索をサポートしていないことを知っています。

PowerShellCmdletファイルをコピーする機能があるかどうかを確認する方法がわかりません。サポートしている場合は、正規表現のファイル名の一致をサポートしているかどうかを確認する方法。

誰かが正規表現のファイル名の一致で再帰的なファイルのコピー/移動を実行する方法を考えることができますか?


1
これはstackoverflowに移動する必要がありますか?
user33788

1
@smoknheap:それは両方かもしれませんが、Powershellスクリプトはますますパワーユーザーツールになりつつあります。これは、xcopyの置換に関する質問ではなく、スクリプトに関する質問です。
Doltknuckle

回答:


5

できる限りすべてのPowershellコマンドを使用するのが好きです。少しテストした後、これが私ができる最善の方法です。

$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter} 
foreach ($item in $bin) {Copy-Item -Path $item.FullName -Destination $destination}

最初の3行は、これを読みやすくするためのものです。必要に応じて、実際のコマンド内で変数を定義できます。このコードサンプルの要点は、正規表現の一致を受け入れるフィルターである「Where-Object」コマンドです。正規表現のサポートは少し変わっていることに注意してください。サポートされている文字が左側にあるPDFリファレンスカードをこちらで見つけました。

[編集]

「@JohannesRössel」で述べたように、最後の2行を1行に減らすこともできます。

((Get-ChildItem -Path $source) -match $filter) | Copy-Item -Destination $destination

主な違いは、ヨハネスの方法はオブジェクトフィルタリングを行い、私の方法はテキストフィルタリングを行うことです。Powershellを使用する場合、ほとんどの場合、オブジェクトを使用する方が適切です。

[編集2]

@smoknheapが述べたように、上記のスクリプトはフォルダー構造を平坦化し、すべてのファイルを1つのフォルダーに入れます。フォルダ構造を保持するスイッチがあるかどうかはわかりません。-Recurseスイッチを試しましたが、役に立ちません。これを機能させる唯一の方法は、文字列操作に戻り、フィルターにフォルダーを追加することです。

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

これを行うにはよりエレガントな方法があると確信していますが、私のテストからはうまくいきます。すべてを収集し、名前の一致とフォルダオブジェクトの両方をフィルタリングします。文字列操作にアクセスするには、ToString()メソッドを使用する必要がありました。

[編集3]

次に、パスを報告して、すべてが正しいことを確認する場合は、「Write-Host」コマンドを使用できます。何が起こっているかについてのヒントを与えるコードは次のとおりです。

cls
$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Write-Host "
----
Obj: $item
Path: "$item.fullname"
Destination: "$item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

これにより、関連する文字列が返されます。どこにも何もない場合は、どのアイテムに問題があるかがわかります。

お役に立てれば


ここで使用する必要はないことに注意してください$item.FullName。FileInfoオブジェクトを渡すと、適切なプロパティが自動的に取得されます(PowerShellの機能は、文字列ではなく構造化オブジェクトを渡すことから得られるためです)。さらに、すべてを単一のパイプラインに入れることができます((gci $source) -match $filter) | cp -dest $destination(簡潔にするために少し変更されています。自由に変更してください。ここでforeachは不要です)。
Joey

テストしているときに、オブジェクトを正しくパイプすることができませんでした。つまり、foreachコマンドを使用する必要があります。私はあなたのコードを試して、何が起こるか見てみましょう。ご指摘いただきありがとうございます。
Doltknuckle

これは、宛先ディレクトリを平坦化する私の問題と同じ問題がありますか?xcopyは通常、宛先ディレクトリのディレクトリ構造を保持しますよね?
user33788 2010年

Copy-Item : Cannot bind argument to parameter 'Path' because it is null
Ian Boyd

Trimは、別の文字列の末尾から文字列を削除することを目的としていないことに注意してください。代わりに、それが呼び出された文字列の先頭と末尾からパラメータ文字列内の文字のすべてのインスタンスを削除します。あなたの場合$item.Name、大文字のCが含まれている場合は、文字列の先頭からドライブ文字Cも削除されます。
Andris

3

PowerShellはそのタスクに最適なツールです。コピープロセスには、Copy-Itemコマンドレットを使用できます。あなたは、複雑なコピーコマンドの他のコマンドレットとパイプラインのそれをすることができ、ここではまさにそれをやった人です:)

正規表現は、System.Text.RegularExpressions名前空間の.NET RegExクラスを使用します。これらのクラスには簡単なハウツーがあります

PowerShellはまた、持っている-matchおよび-replace演算子コピー項目にパイプライン化する際に使用することができます

RegEx自体を作成するのに役立つツールもあります。例:RegEx buddy


Imho、-matchそして-replaceに入る前に言及する必要がありますSystem.Text.RegularExpressions.RegEx。少なくとも私にとっては、[regex]直接使用することはほとんどありません。ただし、私頻繁に-matchand -replace演算子を使用しています。正規表現の作成に関しては、PowerShellが、作成している正規表現のテストと改良にも非常に役立つことがわかりました。
Joey

:私はこの質問では、あなたの答えに答えを求めてきましたsuperuser.com/questions/149808/...
イアン・ボイド

0

アイデアとしてですが、いくつかの作業が必要です

dir -r | ?{$ _ -match '[0-9] {13} \。(gif | jpg | png)'} | %{xcopy $ _。fullname c:\ temp}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.