目的:Powershellの正規表現と置換の習得
- 最終的に作るもの
- C:\work\配下の様々なフォルダ階層にあるファイルを、C:\work2\配下にmoveして集める
- move先でファイル名が重複した場合、「ファイル名_通番.拡張子」にリネームする
- C:\work\配下の様々なフォルダ階層にあるファイルを、C:\work2\配下にmoveして集める
##※書きはじめ2016/1/1 完了予定2016/1/3
####Powershellに親しむことを目的としているため、寄り道、脱線もたくさんします
$FROM = "C:\work"
$MOVETO = "C:\work2"
#ディレクトリリスト取得
$DIR_ = dir ${FROM}
#ディレクトリリストからファイル名一覧取得
$FILENM = ${DIR_}.name
#ディレクトリリストからファイル名フルパス一覧取得
$FULLNM = ${DIR_}.fullname
# if文で、-match演算子を用い、正規表現による文字列検索
foreach ($i in $FILENM) {
# ^ = 右の文字が行頭になる位置条件を表す特殊文字
# $ = 左の文字が行末になる位置条件を表す特殊文字
# 例:文字列"yamamoto"「だけ」にマッチさせる場合
# if ( $i -match ^yamamoto$){処理}
# . = 任意の1文字を表す特殊文字
# * = 繰り返しを表す特殊文字
# \ = エスケープ文字
# 「.txt」の場合は「\.txt」と書いて、特殊文字の意味を消す
# 例:「.txt」の拡張子のファイル名すべてにマッチさせる場合
# if ( $i -match ^.*\.txt$){処理}
# \s = 空白の正規表現
# \S = 空白以外の正規表現
if ( ${i} -match "^.*\S\.txt$") {
write ${i}
}
}
# 拡張子を除いた1番後ろの文字が空白の場合、マッチしない
# "AAAAA.txt"にマッチし、"AAAA .txt"にはマッチしない
# \sは反対
# "AAAA .txt"にマッチし、"AAAAA.txt"にはマッチしない
foreach ($i in $FILENM) {
# \w = 単語
# \W = 単語以外
if ( "${i}" -match "^.*\W..txt$") {
write ${i}
}
}
foreach ($i in $FILENM) {
# \b = 単語の境界
# \B = 単語の境界ではないことを示す
if ( "${i}" -match "^.*\b..txt$") {
write ${i}
}
}
foreach ($i in $FILENM) {
# {n} = 直前の文字のn回の繰り返し このばあいは「.(任意の文字)」を3回
if ( "${i}" -match "^.{3}.txt$") {
write ${i}
}
}
#ren $i ${i}_1.txt
#}
###
##ごちゃごちゃしてきたので作り直し
# やりたいこと
# C:\work\配下の様々なフォルダ階層にある全ファイルを、C:\work2\配下にmoveして集める
# move先でファイル名が重複した場合、「ファイル名_通番.拡張子」にリネームする
# 検索ドライブパス
$DRIVE = "C:"
# 検索の最上位とするフォルダ このフォルダ配下の全ファイルを再帰的に探します
$FROM = "\work"
# 検索したファイルの移動先
$MOVETO = "C:\work2"
# 検索
$DIR_ = dir -Recurse ${DRIVE}${FROM}
# ファイル名一覧取得
$FILENM = ${DIR_}.name
# フルネームで取得
$FULLNM = ${DIR_}.fullname
foreach ($i in $FULLNM) {
# ファイル名にbとcを順不同に含む場合を検出してみる
# if (($i -match "${DRIVE}\${FROM}(\\.*)*\\.*b.*c.*\.(.)*$") -or ($i -match "${DRIVE}\${FROM}(\\.*)*\\.*c.*b.*\.(.)*$")) {
# write $i
# 拡張子の前に「_1」とつけてリネームしてみる
# dir ${i} | rename-item -newname { $_.name -replace '\.(.)*','_1$&' }
#}
#上をコメントアウトしてswitch文で書いてみる
switch -regex ($i) {
"${DRIVE}\${FROM}(\\.*)*\\.*b.*c.*\.(.)*$" {
write $i
}
"${DRIVE}\${FROM}(\\.*)*\\.*c.*b.*\.(.)*$" {
write $i
}
}
dir ${i} | rename-item -newname { $_.name -replace '\.(.)*','_1$&' }
}
}
##ごちゃごちゃしてきたので作り直し2
- だいぶ惜しいところまできた
# C:\work\配下の様々なフォルダ階層にある全ファイルを、C:\work2\配下にmoveして集める
# move先でファイル名が重複した場合、「ファイル名_通番.拡張子」にリネームする
# 検索ドライブパス
$DRIVE = "C:"
# 検索の最上位とするフォルダ このフォルダ配下の全ファイルを再帰的に探します
$FROM = "\work"
# 検索したファイルの移動先
$MOVETO = "C:\work2"
# 検索
$DIR_ = dir -file -Recurse ${DRIVE}${FROM}
# ファイル名一覧取得
$FILENM = ${DIR_}.name
# フルネームで取得
$FULLNM = ${DIR_}.fullname
# 重複ファイル名カウント用ハッシュ
$count = @{}
foreach ($i in $FULLNM) {
$fullpass = $i
$filename = &{split-path "$i" -leaf}
$count.$filename += 1
$counter = $count.$filename
if ("$counter" -ge 2) {
dir ${i} | rename-item -newname { $_.name -replace '\.(.)*','_xxxx$&' }
}
}
#⇓⇓【成功】2016/1/2 21:14 完了
# C:\work\配下の様々なフォルダ階層にある全ファイルを、C:\work2\配下にmoveして集める
# move先でファイル名が重複した場合、「ファイル名_通番.拡張子」にリネームする
# 検索ドライブパス
$DRIVE = "C:"
# 検索の最上位とするフォルダ このフォルダ配下の全ファイルを再帰的に探します
$FROM = "\work"
# 検索したファイルの移動先
$MOVETO = "C:\work2"
# ファイル一覧を取得する
# DIR結果を変数格納
$DIR_ = dir -file -Recurse ${DRIVE}${FROM}
# DIRからファイル名一覧を取得
$FILENM = ${DIR_}.name
# DIRからフルパス(X:\xxxx\xxxx.xxxx)で取得
$FULLNM = ${DIR_}.fullname
# ファイル一覧から、重複したファイル名をリネームする
# ファイル名カウント用に空ハッシュ作成
$count = @{}
# フルパス(X:\xxxx\xxxx.xxxx)で取得した全階層にあるファイル一覧を、1行ずつ読み込み
foreach ($i in $FULLNM) {
# ファイル名を変数格納
$filename = &{split-path "$i" -leaf}
# ファイル名を拡張子なしで変数格納
$noextent = [System.IO.Path]::GetFileNameWithoutExtension($i)
# 拡張子のみを変数格納
$extent = [System.IO.Path]::GetExtension($i)
# ファイル名1つをキーにして、値を1カウントアップ
$count.$filename += 1
# カウントアップした数を変数格納
$counter = ${count}.${filename}
# 重複したファイル名は、カウントアップした数字が2以上になる
if ("$counter" -ge 2) {
# カウントアップした数字をファイル名に付番しリネーム
# ファイル名(フルパス) → ファイル名(拡張子なし)_カウントアップした数_拡張子
ren ${i} -newname ${noextent}_${counter}_${extent}
}
}
# リネームした後にファイル一覧を再取得する
# DIR結果を変数格納
$DIR2_ = dir -file -Recurse ${DRIVE}${FROM}
# DIRからファイル名一覧を取得
$FILENM2 = ${DIR2_}.name
# DIRからフルパス(X:\xxxx\xxxx.xxxx)で取得
$FULLNM2 = ${DIR2_}.fullname
# moveする
foreach ($i in $FULLNM2) {
mv -Path $i -Destination $MOVETO
}
#⇓⇓【追加要件】書き始め:1/3 12:20 完了予定:~1/3中
- 検索したファイルがテキストの場合、中身を読み込んで処理する
- 「:」をデリミタにして、1要素目と2要素目を取り出す
- 正規表現を用いて置換を行う
# ⇒⇒【完了】2016/1/3 15:02 ⇓⇓
# 検索ドライブパス
$DRIVE = "C:"
# 検索の最上位とするフォルダ このフォルダ配下の全ファイルを再帰的に探します
$FROM = "\work"
# 検索したファイルの移動先
$MOVETO = "C:\work2"
# ファイル一覧を取得する
# DIR結果を変数格納
$DIR_ = dir -file -Recurse ${DRIVE}${FROM}
# DIRからファイル名一覧を取得
$FILENM = ${DIR_}.name
# DIRからフルパス(X:\xxxx\xxxx.xxxx)で取得
$FULLNM = ${DIR_}.fullname
# ファイルの中身にある"ccc"という文字列を空白("")に置換する(1/3追加)
foreach ($i in $FULLNM2){
# Get-Content(gc)で読み込んだ1行目($i)のファイルを開く
$readfile = &{gc $i}
# 正規表現で置換
# "ccc"は正規表現で"\bccc\b" (\bは単語の境界)
# ※エスケープシーケンスは不要 (Perlでいうところの\Q"string"\E)
## つまり、"ccbc"などは、検索結果に含まれず、純粋な"ccc"が置換対象となる
$renamed = $readfile -replace "\bccc\b",""
# 置換結果をファイルに上書きする
$renamed >$i
}
# 「:」をデリミタにして区切る
foreach ($i in ${FULLNM}){
# Get-Content(gc)で読み込んだ1行目($i)のファイルを開く
$readfile = &{gc $i}
# split関数に渡して「:」で区切る
$nocolon = $readfile.Split(":")
# ファイル名を拡張子なしで変数格納
$noextent = [System.IO.Path]::GetFileNameWithoutExtension($i)
# 拡張子のみを変数格納
$extent = [System.IO.Path]::GetExtension($i)
# ファイル名をパスのみ取得
$pass_ = [System.IO.Path]::GetDirectoryName($i)
# 保存:元のファイルパス\元のファイル名_nocolon_拡張子
$nocolon >"${pass_}\${noextent}_nocolon_${extent}"
}