web-dev-qa-db-ja.com

Powershellを使用して再帰的にファイル名を変更する

現在、現在いるフォルダー内のファイルの名前をバッチで変更する行があります。

dir | foreach { move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") }

このコードは、現在どのディレクトリにいても完全に機能しますが、11個の子フォルダを含む親フォルダからスクリプトを実行したいです。各フォルダーに個別にナビゲートすることでタスクを実行できますが、スクリプトを1回実行して完了します。

私は次を試しました:

get-childitem -recurse | foreach { move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") }

誰かがここで正しい方向に私を指すことができますか?私はPowershellについてあまり詳しくありませんが、この場合の私のニーズに合っていました。

21
Matthew

あなたは近かった:

Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(".mkv.mp4",".mp4")}
28
Cole9350

まさにこのシナリオ用に設計されたあまり知られていない機能があります。簡単に言うと、次のようなことができます。

Get-ChildItem -Recurse -Include *.ps1 | Rename-Item -NewName { $_.Name.replace(".ps1",".ps1.bak") }

これにより、パラメーターNewNameのスクリプトブロックを渡すことにより、ForEach-Objectを使用する必要がなくなります。 PowerShellは、パイプ処理される各オブジェクトのスクリプトブロックを十分に評価し、ForEach-Objectの場合と同様に$ _を設定します。

32
Jason Shirk

stillCannot rename because item at '...' does not exist.などのエラーに問題がある場合、いくつかの超長いパスや角括弧などの「特別に解釈された」文字(つまり[])。

このようなシナリオでは、最大32k文字のパスに特別な接頭辞-LiteralPathとともに-PSPath/\\?\を使用します(UNCパスの場合、接頭辞\\?\UNC\を使用します)。また、パフォーマンスを向上させるために(Get-ChildItemを使用して)早期にフィルタリングすることをお勧めします(Rename-Item呼び出しが少ないほど優れています)。


$path = 'C:\Users\Richard\Downloads\[Long Path] THE PATH TO HAPPINESS (NOT CLICKBAIT)\...etc., etc.'
# -s is an alias for -Recurse
# -File for files only
# gci, dir, and ls are all aliases for Get-ChildItem
#   Note that among the 3, only `gci` is ReadOnly.
gci -s -PSPath $path -File -Filter "*.mkv.mp4" |
    # ren, rni are both aliases for Rename-Item
    #   Note that among the 2, only `rni` is ReadOnly.
    # -wi is for -WhatIf (a dry run basically). Remove this to actually do stuff.
    # I used -replace for regex (for excluding those super rare cases)
  rni -wi -PSPath { "\\?\$($_.FullName)" } -NewName { $_.Name -replace '\.mkv(?=\.mp4$)','' }
0
YenForYang