今回はパワーシェルでファイル名の一部を取得(切り出し)して、変数に格納する
##構成環境
- Windows10
- PowerShell 5.1
例えば以下のようなファイル構成とするとき
PS C:\user\xyz>Get-ChildItem -Name
1101agalaga.xyz
1102gkjghah.xyz
1103gglaglafdg.xyz
1104yagahgh.xyz
1105xb1agal.xyz
1101~1105.log
example.sys
Rename.ps1
SubString.ps1
上記xyzフォルダ内の*.xyzファイルの1文字目から4文字目を取得(さらにどのxyzファイルかを指定)
特定のファイル一覧の中で一貫性のある日付部分の情報を得るなど
##特定のファイル一覧の中で任意の文字列に一致するものを取得
$path="C:\user\xyz"
#拡張子を除くファイル名を取得
$file=(Get-ChildItem $path\*xyz).BaseName
#1文字目から4文字目を変数に格納
foreach($list in $file.SubString(0,3)){
#1101と1102を取得する場合
if($list-eq"1101"){
$first=$list
}
if($list-eq"1102"){
$second=$list
}
}
Write-Host "first="$first
Write-Host "second="$second
実行例
first= 1101
second= 1102
...あれ、よく見たらこれ任意の文字列をただ出力しただけであんまり意味がないコードでした
##ファイル名の任意の文字列の最初と最後を取得したいとき
以下のようにすると良いかも
###続き$path=C:\user\xyz,$file=(Get-ChildItem $path\*xyz).BaseName
#xyzファイルの個数を取得
$total_xyz=(Get-ChildItem $path\*xyz | Measure-Object).Count
$counter=0
##1文字目から4文字目を変数に格納
foreach($list in $file.SubString(0,3)){
#最初と最後を変数に格納(欲しい文字列が不明なときなど)
if($counter-eq"0"){
$first=$list
}
$counter+=1
if($counter-eq$total_xyz){
$last=$list
}
}
Write-Host "first="$first
Write-Host "last="$last
最初と最後はカウンターで判定してみた
実行例
first= 1101
last= 1105
普通にもっと良い方法がある気がする
とりあえずこれでやりたいことはできた
##※ファイル名の任意の文字列の最初と最後を取得する最適解
ファイルの拡張子を除くファイル名に対して、前方の数値に一致する箇所が正規表現で一致したとき配列[0]に格納して、配列[0]の最初と最後を取得したものをパイプでつないでGet-ChildItem
すると...
なんと一行でできるみたい
Get-ChildItem C:\User\xyz | Foreach-Object { if ($_.BaseName -match "^\d+") { $Matches[0] } } | Select-Object -First 1 -Last 1
##結論
普通にもっと良い方法があった
##その他の文字列の最初と最後の取得パターン
- 上記を参考にファイル名の最後尾の文字列の最初と最後の要素を取得
###続き$path=C:\user\xyz
#ファイル名の最後の要素を取得
$get_childitem_match=Get-ChildItem $path\*xyz | Foreach-Object { if ($_.BaseName -match ".$") { $Matches[0] } }
#取得した要素の最初と最後を変数に格納
$Last_First=$get_childitem_match | Select-Object -First 1 -Last 0
$Last_Last=$get_childitem_match | Select-Object -First 0 -Last 1
Write-Host "first ="$Last_First
Write-Host "last ="$Last_Last
実行例
first = a
last = l
- 文字列中の任意の箇所の最初と最後を取得
###続き$path=C:\user\xyz
##ファイル名の任意の要素(4文字目から6文字目)を取得
$get_childitem_match_substring=(Get-ChildItem $path\*dbg).BaseName | Foreach-Object { if($_.SubString(3,5) -match "...") {$Matches[0]} }
#取得した要素の最初と最後を変数に格納
$substring_first=$get_childitem_match_substring | Select-Object -First 1 -Last 0
$substring_last=$get_childitem_match_substring | Select-Object -First 0 -Last 1
Write-Host "first ="$substring_first
Write-Host "last ="$substring_last
実行例
first = 1ag
last = 5xb
正規表現とSubStringを組み合わせてみたが、正規表現だけでどうにかならないか...
##正規表現のグループを使う
今回の場合例えばSubString(3,5)
を表現したいときは
Foreach-Object { if($_. -match "(\d{3})(.{3})") {$Matches[2]} }
もしくは、他のファイル名のパターンにもマッチしようとするならば
Foreach-Object { if($_. -match "(.{3})(.{3})") {$Matches[2]} }
こんな感じだろうか
###まてよ...?
Foreach-Object { if($_. -match "(^\d+)(.$)") {$Matches[0]} }
と思いやってみたが、何も表示されなかった...
Foreach-Object { if($_. -match "(^\d+)(\w{1,})(.$)") {$Matches[1],$Matches[3]} }
これならよさそうだけど、$Matches[1]
と$Matches[3]
それぞれ最初と最後の取得が上手くできないか...残念
##参考
##余談
@コマンドプロンプトでいうpauseみたいなのがないかなとか思ってたけど、そのままpause
を入力するとEnterキーの入力待ちになるようです
Read-Host "続行するには、Enter キーを押してください..."
でもいいみたい
詳しくは以下のサイト様など
PowerShell でコマンドプロンプトの Pause コマンドっぽいヤツ
##最後に
実際にこのコードが何に使えるのかは知る由もありませんが、何かしらのアイデアの糧になればと思います
正規表現と比較演算子で結構いろんなことができるのでもっと使えるようになりたい
パワーシェルの実行ファイル(.ps1)の名前にカッコ()を使うと特殊な挙動になるのが謎