forLifeMap

仕事、投資、技術メモ、オカルト、その他クソミソな趣味や日常についてあれこれ綴る、日記帳というより雑記帳。忘却の彼方に置き忘れた夢と情熱を求めて彷徨中。

ROBOCOPYの堕とし穴

ROBOCOPYの設定値で思いのほか
苦労してしまったので、備忘録メモ。

やりたいこと

簡単のため「Terapad」を例に出すと、

History.txt
Keys.txt
Readme.txt
TeraPad.exe
usr.txt

 という5つのファイルが

C:\test\Terapad

というフォルダに入っており、
この「Terapad」フォルダごと

D:\Terapad

として、ROBOCOPYでコピーしたい。

ハマったこと

通常、ROBOCOPYのコマンドは

ROBOCOPY <src> <dest> [<file> <options>]

という指定をする。
上記の「やりたいこと」を実現しようとすると、

ROBOCOPY "C:\test\Terapad" "D:"

でいいのかな、と安易に考えていた。
それが大いなる勘違いだった。

上記のコマンドを実行すると、
Dドライブ直下に

History.txt
Keys.txt
Readme.txt
TeraPad.exe
usr.txt

がブチ撒けられてしまう。

f:id:hNeumann:20171110010233j:plain


確かに、よくよくROBOCOPYの仕様を
読んでみると、まぁ確かにそうなんだけど。
でもこんな形のコピーは全く望んでいない。

力技で解決

ウンウンと色々悩んだ末に、力技で解決。
諸事情によりPowershellでゴリゴリ記述。

# コピー元のフルパス
$srcpath = "C:\test\Terapad"
# コピー先のフルパス
$dstroot = "D:\"

# オブジェクト種別によってコピーオプション変更
# $srcpathがフォルダかファイルか判定する
$isDir = Get-Item $srcpath | Where-Object{$_.PSIsContainer}

# フォルダの場合
if($isDir){

# 「Terapad」のフォルダ名を取得
$dirname = [System.IO.Path]::GetFileName($srcpath)

# 出力先に「Terapad」フォルダ名を作成
$dstpath = $dstroot + $dirname
New-Item $dstpath -itemType Directory > $null

# 遠慮なくROBOCOPYでブチ撒ける
ROBOCOPY $srcpath $dstpath /E > $null

# ファイルの場合
}else{

# コピー元のファイル名を取得
$filename = [System.IO.Path]::GetFileName($srcpath)

# コピー元の親フォルダを取得
$srcpath = Split-Path $srcpath -parent

# 対象ファイルをブチ撒ける
ROBOCOPY $srcpath $dstroot $filename > $null
}

 なお、上記ソースは、コピー元のパスが
ファイルの場合もフォルダの場合も対応している。

うーん。
もっとスマートなやり方が
あるのだろうか…