LoginSignup
1
1

More than 5 years have passed since last update.

Get-ChildItemの結果を元にファイルをリネームするときの注意(重複操作)

Posted at

ファイルシステムに対するGet-ChildItemの結果を元にファイルのリネームなどを行う場合、同じファイルに対して複数回操作してしまうことがある、という話。

よくある話だと思いますが、ちょっとハマったので備忘録としてメモ。

環境

Windows 8.1 Pro
Windows PowerShell 4.0

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.3.9600.18968
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

問題となる例

サンプルコード

# 事前準備
# ユーザーのドキュメントフォルダに適当な名前のフォルダを作成
# カレントディレクトリへ変更
[IO.Path]::Combine( #
    [System.Environment]::GetFolderPath('MyDocuments'),
    [guid]::NewGuid()
) | New-Item -Path {$_} -ItemType Directory |
    Push-Location -LiteralPath {$_.FullName}
# 1.log .. 10.log というファイルを作る
1..10 |
    New-Item -Name {'{0}{1}' -f $_ , '.log'} -ItemType File > $null


# 問題の箇所
# .logのファイルに今日の日付(yyyyMMdd)をつけてリネーム
Get-ChildItem -Filter *.log | 
    Rename-Item -NewName {
        '{0}-{1}' -f $_.Name , 
                     (Get-Date -Format yyyyMMdd) 
    } -PassThru

サンプルの実行結果

この時のコンソール出力(=Rename-Itemが変更したファイル)は以下のようになる。

    ディレクトリ: C:\Users\username\Documents\7a9baef0-bb8b-44e0-a3d4-7cc871f875b2


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          18/08/16     20:01          1 1.log-20180816
-a---          18/08/16     20:01          2 10.log-20180816
-a---          18/08/16     20:01          1 1.log-20180816-20180816
-a---          18/08/16     20:01          1 2.log-20180816
-a---          18/08/16     20:01          1 3.log-20180816
-a---          18/08/16     20:01          1 4.log-20180816
-a---          18/08/16     20:01          1 5.log-20180816
-a---          18/08/16     20:01          1 6.log-20180816
-a---          18/08/16     20:01          1 7.log-20180816
-a---          18/08/16     20:01          1 8.log-20180816
-a---          18/08/16     20:01          1 9.log-20180816

出力を見ると1.logに対して2回処理が行われているのが確認できる。

image.png

原因と対策

原因

Rename-Itemは逐次実行のため、Get-ChildItemのパイプライン出力1個毎に処理をする。
つまり、ファイルが1個見つかるたびそのファイルの名前が変更される。

ファイルの名前が変わることで内部的な並び順が変わり、名前によってはGet-ChildItemによって同じファイルが再度パイプラインに出力される、
そのため複数回同じ処理をしてしまう、
ということだと思われる。

対策

Get-ChildItemの出力結果を固定すれば良いので、以下のような方法が考えられます(もっと良い方法があれば教えて下さい)。

  • Get-ChildItemの結果を変数に入れる
  • Get-ChildItemを括弧でくくる
  • Sort-Objectなど全結果を一度キャッシュするコマンドを挟む
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1